是否在rewrite时启动forward到一个新的Origin服务器的动作,如果是则代理转发到新的URL
是否为正向代理,正向代理的请求地址request URI是绝对URI,如果是则代理转发到绝对URI上
判断当前资源位置HTTPLoc是否配置了反向代理,以及反向代理指向的Origin服务器,如果是,根据规则生成访问Origin服务器的URL地址
以上三种情况中,第一种和第三种为反向代理,第二种为正向代理,对应的配置样例如下:
location = { #rewrite ... forward type = server; path = ['/5g/', '^~' ]; script = { rewrite ^/5g/.*tpl$ http://temple.ejetsrv.com/getres.php forword; }}# HTTP请求行是绝对URI地址GET http://cdn.ejetsrv.com/view/23C87F23D909B47E2187A0DB83AF07D3 HTTP/1.1....location = { # 反向代理配置 path = [ '^/view/([0-9A-Fa-f]{32})$', '~*' ]; type = proxy; passurl = http://cdn.ejetsrv.com/view/$1;......}
无论是正向代理,还是反向代理,最后转发请求的操作流程基本类似,即需明确指向新Origin服务器的URL地址,作为下一步转发地址,主动建立到Origin服务器的HTTPCon连接,组装新的HTTPMsg请求,发送请求并等候响应,将响应结果转发到源HTTPMsg中,发送给客户端。
如果是代理请求,包括正向代理或反向代理,eJet需要做Proxy代理转发处理。
9.2 代理请求的实时转发
需要重点介绍的是实时转发源请求到Origin服务器的流程。代理转发时先创建一个代理转发的HTTPMsg实例,将源请求HTTPMsg实例的请求数据复制到代理请求HTTPMsg中,如果HTTP请求含有请求消息体时,代理转发流程有两种实现方式:
一种方式是存储转发,即接收完所有的HTTP请求消息体后,再复制到代理转发HTTPMsg中,最后发送出去
另一种方式实时转发,即接收一部分消息体就发送一部分消息体,直到全部发送完毕
为了确保代理转发效率和降低存储消耗,eJet系统采用实时转发模式。
源请求的消息体内容保存在HTTPCon的rcvstream中,响应IOE_READ事件时将网络内容读取到该缓冲区后,就要调用http_proxy_srv_send来实时转发。转发的数据包括代理请求头、上次未发送成功的消息体、及当期位于HTTPCon缓冲区中的rcvstream,严格按照接收的顺序来发送。
每次未发送成功的消息体,将会从HTTPCon的rcvstream中拷贝出来,转存到代理请求HTTPMsg中的req_body_stream中,作为临时缓冲区保存累次未能发送的消息体。当从源HTTPCon中接收到新数据、或到Origin服务器的目的HTTPCon中可写就绪时,都会启动http_proxy_srv_send的实时发送流程,而优先发送的消息体就是代理请求中req_body_stream中的内容。
源请求的消息体有三种情况:
没有消息体内容
存在以Content-Length来标识大小的消息体内容
存在以Transfer-Encoding标识分块传输编码的消息体内容
实时转发需要处理这三种情况,最终通过http_con_writev来发送给对方。发送不成功的剩余内容,需要从源HTTPCon中拷贝到代理请求HTTPMsg中的req_body_stream中。
实时转发最大问题是拥塞问题,即源HTTPCon上的请求数据发送速度很快,但到Origin服务器的目的HTTPCon连接的发送速度比较慢,导致大量的数据会堆积到代理消息HTTPMsg中req_body_stream中,消耗大量内存,严重时会导致内存消耗过大系统崩溃。
代理消息实时转发模式的拥塞问题根源在于两条线路传输速度不对等导致,只要发送侧速度大于接收侧速度,拥塞问题就会出现。解决拥塞问题需从源头来考虑,判断是否拥塞的标准是堆积的内存缓冲区超过一定的阈值,一旦内存堆积超过阈值,就断定为拥塞,需限制客户端继续发送任何内容,直到解除拥塞后继续发送。
9.3 代理响应的实时转发
代理请求转发给Origin服务器后,会返回响应消息,包括响应头和响应体,eJet处理响应头的接收和处理编码。
和HTTP请求消息的实时转发类似,代理消息的响应也需要实时转发给客户端。
根据代理HTTPMsg内部成员proxiedl连判断当前消息是否为代理,对Origin返回的响应头信息进行预处理:
如果是301/302跳转,当前代理消息是反向代理,并且系统允许自动重定向,则需重新发送重定向请求;
如果需要缓存到本地存储系统,采用缓存处理流程,见4.20章节