<-
Apache HTTP 服务器 2.4 > Apache模块mod_proxy_ajp

Apache模块mod_proxy_ajp

描述:AJP支持模块 mod_proxy
状态:延期
模块标识符:proxy_ajp_module
源文件:mod_proxy_ajp.c
兼容性:在2.1版及更高版本中可用

摘要

此模块需要的服务mod_proxy。它为Apache JServ Protocol version 1.3(以下称为 AJP13)提供支持 。

因此,为了得到处理的能力AJP13 协议,mod_proxymod_proxy_ajp具有存在于该服务器。

警告

确保服务器安全之前,请勿启用代理。开放式代理服务器对您的网络和整个Internet都是危险的。

支持Apache!

主题

指令

该模块不提供指令。

错误修正清单

也可以看看

最佳

用法

该模块用于使用AJP13协议将代理反向代理到后端应用程序服务器(例如Apache Tomcat)。用法类似于HTTP反向代理,但使用ajp://前缀:

简单反向代理

ProxyPass "/app" "ajp://backend.example.com:8009/app"

还可以使用平衡器:

平衡器反向代理

<Proxy "balancer://cluster">
    BalancerMember "ajp://app1.example.com:8009" loadfactor=1
    BalancerMember "ajp://app2.example.com:8009" loadfactor=2
    ProxySet lbmethod=bytraffic
</Proxy>
ProxyPass "/app" "balancer://cluster/app"

请注意,通常不需要任何 ProxyPassReverse 指令。AJP请求包括提供给代理的原始主机标头,并且可以期望应用程序服务器生成相对于此主机的自引用标头,因此无需重写。

主要的例外是代理上的URL路径与后端上的URL路径不同。在这种情况下,可以相对于原始主机URL(而不是后端ajp://URL)重写重定向头,例如:

重写代理路径

ProxyPass "/apps/foo" "ajp://backend.example.com:8009/foo"
ProxyPassReverse "/apps/foo" "http://www.example.com/foo"

但是,通常最好将应用程序以与代理相同的路径部署在后端服务器上,而不是采用这种方法。

最佳

环境变量

名称带有前缀的环境变量AJP_ 将作为AJP请求属性转发到原始服务器(从密钥名称中删除AJP_前缀)。

最佳

协议概述

AJP13协议是面向分组的。出于性能考虑,大概选择了更具可读性的纯文本格式的二进制格式。Web服务器通过TCP连接与Servlet容器进行通信。为了减少昂贵的套接字创建过程,Web服务器将尝试维护与Servlet容器的持久TCP连接,并在多个请求/响应周期中重用连接。

将连接分配给特定请求后,在请求处理周期终止之前,该连接将不再用于其他任何请求。换句话说,请求不会通过连接进行多路复用。尽管这样做确实会导致同时打开更多连接,但是这会使连接两端的代码更加简单。

Web服务器打开与servlet容器的连接后,该连接可以处于以下状态之一:

一旦分配了连接以处理特定请求,就以高度压缩的形式(例如,将通用字符串编码为整数)在连接上发送基本请求信息(例如HTTP标头等)。该格式的详细信息在下面的“请求数据包结构”中。如果请求有正文(content-length > 0),则在随后的单独数据包中发送该正文。

此时,servlet容器可能已准备好开始处理请求。这样,它可以将以下消息发送回Web服务器:

每个消息都带有不同格式的数据包。有关详细信息,请参见下面的响应数据包结构。

最佳

基本封包结构

该协议有一些XDR传统,但是在很多方面都存在差异(例如,没有4字节对齐)。

AJP13对所有数据类型使用网络字节顺序。

协议中有四种数据类型:字节,布尔值,整数和字符串。

字节
一个字节。
布尔型
单字节,1 = true0 = false。在某些地方使用其他非零值作为true(即C样式)可能会起作用,但在其他地方则不会。
整数
范围内的数字0 to 2^16 (32768)。存储在2个字节中,高位在前。
可变大小的字符串(长度以2 ^ 16为界)。编码时先将长度打包成两个字节,然后是字符串(包括终止符'\ 0')。注意,编码长度不会 包括尾部“\ 0” -它像 strlen。在Java方面,这让人有些困惑,因为到处都是奇怪的自动增量语句,以跳过这些终止符。我相信这样做是为了让C代码在读取servlet容器发送回的字符串时更加高效-使用终止符\ 0,C代码可以将引用传递到单个缓冲区中,而无需复制。如果缺少\ 0,则C代码必须将内容复制出来才能获得其字符串概念。

封包大小

根据大部分代码,最大数据包大小为 8 * 1024 bytes (8K)。数据包的实际长度在标头中编码。

包头

从服务器发送到容器的数据包以开头 0x1234。从容器发送到服务器的数据包以AB(这是A的ASCII码,然后是B的ASCII码)开头。在前两个字节之后,有一个有效载荷长度的整数(按上面的编码)。尽管这可能表明最大有效载荷可能高达2 ^ 16,但实际上,代码将最大有效载荷设置为8K。

数据包格式(服务器->容器)
字节 0 1个 2 3 4 ...(n + 3)
内容 0x12 0x34 资料长度(n) 数据
数据包格式(容器->服务器)
字节 0 1个 2 3 4 ...(n + 3)
内容 一个 资料长度(n) 数据

对于大多数数据包,有效载荷的第一个字节对消息的类型进行编码。从服务器发送到容器的请求主体数据包是一个例外-它们使用标准数据包头( 0x1234然后是数据包的长度)发送,但之后没有任何前缀代码。

Web服务器可以将以下消息发送到Servlet容器:

包类型 含义
2 转发请求 使用以下数据开始请求处理周期
7 关掉 Web服务器要求容器关闭自身。
8 Web服务器要求容器进行控制(安全登录阶段)。
10 ing Web服务器要求容器用CPong快速响应。
没有 数据 大小(2个字节)和相应的正文数据。

为了确保一些基本的安全性,只有Shutdown在请求来自与其托管的同一台计算机上时,容器才会实际执行操作 。

第一个Data数据包Forward Request在Web服务器之后立即发送 。

Servlet容器可以将以下类型的消息发送到Web服务器:

包类型 含义
3 发送身体块 将主体的一部分从Servlet容器发送到Web服务器(大概发送到浏览器)。
4 发送标题 将响应标头从servlet容器发送到Web服务器(大概发送到浏览器)。
5 结束回应 标记响应的结束(并因此标记请求处理周期)。
6 得到身体块 如果请求尚未全部传输,请从请求中获取更多数据。
9 CPong回复 对CPing请求的回复

以上每个消息都有一个不同的内部结构,下面将详细介绍。

最佳

请求报文结构

对于从服务器到类型为Forward Request的容器的消息 :

AJP13_FORWARD_REQUEST :=
    prefix_code      (byte) 0x02 = JK_AJP13_FORWARD_REQUEST
    method           (byte)
    protocol         (string)
    req_uri          (string)
    remote_addr      (string)
    remote_host      (string)
    server_name      (string)
    server_port      (integer)
    is_ssl           (boolean)
    num_headers      (integer)
    request_headers *(req_header_name req_header_value)
    attributes      *(attribut_name attribute_value)
    request_terminator (byte) OxFF

request_headers具有以下结构:

req_header_name :=
    sc_req_header_name | (string)  [see below for how this is parsed]

sc_req_header_name := 0xA0xx (integer)

req_header_value := (string)

attributes是可选的,具有以下结构:

attribute_name := sc_a_name | (sc_a_req_attribute string)

attribute_value := (string)

并不是最重要的标头是content-length,因为它确定容器是否立即查找另一个数据包。

转发请求要素的详细说明

请求前缀

对于所有请求,该值为2。有关其他前缀代码的详细信息,请参见上文。

方法

HTTP方法,编码为一个字节:

指令名称
选项1个
得到2
3
开机自检4
5
删除6
跟踪7
PROPFIND8
道具9
MKCOL10
复制11
移动12
13
开锁14
访问控制列表15
报告16
版本控制17
报到18岁
查看19
取消结帐20
搜索21
麦考克空间22
更新23
标签24
合并25
BASELINE_CONTROL26
活动能力27

更高版本的ajp13,将传输其他方法,即使它们不在此列表中也是如此。

协议,req_uri,remote_addr,remote_host,server_name,server_port,is_ssl

这些都是不言自明的。这些都是必需的,并将针对每个请求发送。

标头

其结构request_headers如下:首先,对报头数进行num_headers编码。然后,出现一系列标题名称req_header_name/值 req_header_value对。通用标头名称编码为整数,以节省空间。如果标头名称不在基本标头列表中,则它会正常编码(作为字符串,带有前缀长度)。常见标头sc_req_header_name及其代码的列表如下(均区分大小写):

名称代码值代码名称
接受0xA001SC_REQ_ACCEPT
接受字符集0xA002SC_REQ_ACCEPT_CHARSET
接受编码0xA003SC_REQ_ACCEPT_ENCODING
接受语言0xA004SC_REQ_ACCEPT_LANGUAGE
授权书0xA005SC_REQ_AUTHORIZATION
连接0xA006SC_REQ_CONNECTION
内容类型0xA007SC_REQ_CONTENT_TYPE
内容长度0xA008SC_REQ_CONTENT_LENGTH
曲奇饼0xA009SC_REQ_COOKIE
cookie20xA00ASC_REQ_COOKIE2
主办0xA00BSC_REQ_HOST
语用0xA00CSC_REQ_PRAGMA
推荐人0xA00DSC_REQ_REFERER
用户代理0xA00ESC_REQ_USER_AGENT

读取此内容的Java代码将抓取前两个字节的整数,并且如果'0xA0'在最高有效字节中看到,则会使用第二个字节中的整数作为标头名称数组的索引。如果第一个字节不是0xA0,则假定两个字节的整数是字符串的长度,然后将其读入。

这是基于这样的假设,即没有头名称的长度应大于0x9FFF (==0xA000 - 1),这是完全合理的,尽管有些武断。

注意:

content-length头部是非常重要的。如果存在且不为零,则容器假定该请求具有主体(例如POST请求),并立即从输入流中读取单独的数据包以获取该主体。

属性

带有前缀? (例如?context)的属性都是可选的。对于每个属性,只有一个字节码来指示属性的类型,然后是其值(字符串或整数)。它们可以以任何顺序发送(尽管C代码始终按下面列出的顺序发送它们)。发送一个特殊的终止代码来表示可选属性列表的结尾。字节码列表为:

信息代码值价值类型注意
上下文0x01--目前尚未实施
servlet_path0x02--目前尚未实施
?remote_user0x03
?auth_type0x04
?请求参数0x05
?jvm_route0x06
?ssl_cert0x07
?ssl_cipher0x08
?ssl_session0x09
?req_attribute0x0A名称(属性名称如下)
?ssl_key_size0x0B整数
?秘密0x0C从2.4.42开始支持
完成0xFF--request_terminator

contextservlet_path目前不被C代码设置,并且无论是在发送这些字段(如果一个字符串的代码中的一个后一起发送一些它实际上将打破)大部分的Java代码的完全忽略。我不知道这是错误还是未实现的功能,或者仅仅是残留代码,但连接的两侧都没有。

remote_userauth_type可能是指HTTP级认证,并进行通信远程用户的用户名和用于建立他们的身份(例如基本,摘要)身份验证的类型。

query_stringssl_certssl_cipher,和ssl_session指HTTP和HTTPS的对应件。

jvm_route,用于支持粘性会话-关联用户与多个,负载平衡服务器存在一个特定的Tomcat实例雪村。

除了基本属性列表之外,还可以通过req_attributecode 发送任意数量的其他属性0x0A。在该代码的每个实例之后立即发送一对代表属性名称和值的字符串。环境值通过此方法传递。

最后,在发送完所有属性后,将发送属性终止符0xFF。这不仅向属性列表的末尾发出信号,而且还向请求数据包的结束发出信号。

最佳

响应包结构

容器可以发送回服务器的消息。

AJP13_SEND_BODY_CHUNK :=
  prefix_code   3
  chunk_length  (integer)
  chunk        *(byte)
  chunk_terminator (byte) Ox00


AJP13_SEND_HEADERS :=
  prefix_code       4
  http_status_code  (integer)
  http_status_msg   (string)
  num_headers       (integer)
  response_headers *(res_header_name header_value)

res_header_name :=
    sc_res_header_name | (string)   [see below for how this is parsed]

sc_res_header_name := 0xA0 (byte)

header_value := (string)

AJP13_END_RESPONSE :=
  prefix_code       5
  reuse             (boolean)


AJP13_GET_BODY_CHUNK :=
  prefix_code       6
  requested_length  (integer)

细节:

发送身体块

块基本上是二进制数据,并直接发送回浏览器。

发送标题

状态代码和消息是常见的HTTP内容(例如200OK)。响应头名称的编码方式与请求头名称的编码方式相同。有关如何将代码与字符串区分开的详细信息,请参见上面的header_encoding。
常见标头的代码为:

名称代码值
内容类型0xA001
内容语言0xA002
内容长度0xA003
日期0xA004
最后修改0xA005
位置0xA006
Set-Cookie0xA007
Set-Cookie20xA008
Servlet引擎0xA009
状态0xA00A
WWW认证0xA00B

在代码或字符串标题名称之后,标题值立即被编码。

结束回应

发出此请求处理周期结束的信号。如果该 reuse标志为true (anything other than 0 in the actual C code),则此TCP连接现在可用于处理新的传入请求。如果reuse为假(== 0),则应关闭连接。

得到身体块

容器从请求中请求更多数据(如果主体太大而无法容纳发送过来的第一个数据包,或者请求被分块时)。服务器将发送回带有一个数据量的主体数据包,该数据量是的最小值request_length,最大发送主体大小(8186 (8 Kbytes - 6))以及从请求主体实际剩余要发送的字节数。
如果主体中没有更多数据(即servlet容器正尝试读取主体的末尾),则服务器将发回一个 数据包,该数据包是有效载荷长度为0的主体数据包。 (0x12,0x34,0x00,0x00)

可用语言: zh  |  fr  |  ja 

最佳

注释

注意:
这不是“问答”部分。此处放置的评论应指向有关改进文档或服务器的建议,如果实施或被认为无效/偏离主题,我们的主持人可以将其删除。有关如何管理Apache HTTP Server的问题,应直接指向我们的IRC频道#httpd(位于Freenode上),或发送至我们的邮件列表
目前,此页面已禁用评论。