`
desert3
  • 浏览: 2138667 次
  • 性别: Icon_minigender_1
  • 来自: 合肥
社区版块
存档分类
最新评论

Tomcat源码分析--HTTP,AJP请求内部处理流程

 
阅读更多
HTTP 1.1
server.xml配置使用HTTP1.1处理请求
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>

AJP1.3协议Apache和Tomcat集成时使用,Apache处理静态内容,使用Apache的SSL,在很多应用环境下,比通过HTTP协议来访问单独的Tomcat有更加好的性能。在用户结合Engine的jvmRoute属性做loadbalance的时候使用到)
配置:
<Connector address="localhost" port="8081" protocol="AJP/1.3" redirectPort="8443" connectionTimeout="600000"/>

Tomcat内部处理流程
1,HTTP请求发过来后,Tomcat从自己的线程池中提起出一个线程来处理
2,入口org.apache.tomcat.util.net.JIoEndpoint,该类用来处理传递进来的TCP连接,它实现了一个简单的服务器模式:一个监听线程用来接收socket以及为每个进来的连接创建一个worker来处理。更加高级的功能会涉及到线程重用,如队列等。
2#,入口org.apache.tomcat.util.net.AprEndpoint(APR定制线程池,提供Socket接收线程,Socket轮询线程,文件传输线程,Workers线程池);主方法run()监听进来的TCP/IP连接,并用合适的processor来处理。
3,根据Server.xml中配置的协议HTTP/1.1,调用org.apache.coyote.http11.Http11Protocol来后续处理。该类是HTTP1.1协议的实现类,包括线程功能。它处理单个线程和基于流的协议。但是不适用与JK协议如JNDI。主方法process(Socket socket)的内容如下:
  • a.从recycledProcessors中提取已有的processor,如果提取不到,那么创建一个(创建的时候会设置上HTTP1.1相应的一些属性如keepAliveTimeout以及生成request和response信息。注意此时request中还不包括画面提交上来的HTTP Header和Parameters等信息)
  • b.SSL相关设置
  • c.调用processor的process方法进行处理

3#,根据Server.xml中配置的协议AJP/1.3,调用org.apache.coyote.ajp.AjpAprProtocol来后续处理。主方法process(long socket)处理类似,如果从池中提取不到合适的processor,就生成并设置先关属性,然后调用processor的process方法。
4,org.apache.coyote.http11.Http11Processor该类用来处理HTTP请求。主方法process(Socket socket)的内容如下:
  • a.设置socket相关的地址变量和IO信息,即把socket.getInputStream()和socket.getOutputStream()转进来。其他socket.getInputStream()设置给InternalInputBuffer
  • b.调用InternalInputBuffer的parseRequestLine和parseHeader方法,把HTTP请求头内的相关信息读取处理,并使用prepareRequest方法保存到request中的相关变量上去。这时,HTTP Method, HTTP URI, HTTP QUERY STRING, HTTP PROTOCOL的值都是在这里被读取进来,这时候的URI还是没有被解码的,即还含有%XX的信息。
  • c.调用org.apache.catalina.connector.CoyoteAdapter的service方法继续处理

4#,org.apache.coyote.ajp.AjpAprProcessor的处理类似
5,CoyoteAdapter类实现了一个请求处理器(request processor),用来代理处置Coyote processor。主方法service(org.apache.coyote.Request req, org.apache.coyote.Response res)主要内容如下:
  • a.根据Connector来创建相应的Servlet Request和Servlet Response,并把connector配置中的getURIEncoding保存读取出来设置到QueryStringEncoding中,后面给QueryString解码的时候可能使用到,也可能被useBodyEncodingForURI覆盖!
  • b.调用postParseRequest方法处理其他的请求参数, 如果参数是通过HTTP POST方式传递进来的,那么把对应的比特数组存储起来,在第一次通过Request.getParameterValue()访问的时候解码得到真正的参数值,如果参数是通过HTTP GET方式传递进来,那么看connector.getURIEncoding有值,有的话在就用指定的字符集把未解码的URI对应的比特数组解码得到相应的值,否则直接读取未解码的字符,这也不会有问题,因为根据URI规范,URI采用US-ACSII编码,这时候的读取的char,还是有意义的,如%xx的形式。
  • c.调用Catalina引擎继续处理

6,org.apache.catalina.core.StandardEngineValve(默认的StandardEngine引擎实现)
  • a.主方法invoke(Request request, Response response),根据请求的server name,选取合适的Host继续处理请求

7,StandHost选择
  • a.org.apache.catalina.valves.AccessLogValve处理访问日志
  • b.org.apache.catalina.valves.ErrorReportValve根据response状态,输出相应的错误页面

8,org.apache.catalina.core. StandardContextValve(默认的StandardContext实现),处理和webapps下面具体项目的情况,如不允许请求直接访问项目下的/WEB-INF和/WEB-INF目录
9,org.apache.catalina.core. StandardWrapperValve(默认的StandardWrapper实现),调用和请求匹配的Servlet并Servlet的生命周期(如果Servlet有对应的filter,那么就调用它)和SingleThreadModel单线程模式的支持
10,org.apache.catalina.core. ApplicationFilterChain,实现了javax.servlet.FilterChain用来管理每个请求对应的Filter链的执行,所有Filter执行完成后调用servlet的service方法
11,javax.servlet.http.HttpServlet把ServletRequest请求转换成HttpServletRequest,调用相应Servlet的service方法提供服务。如果使用的是Struts框架,那么使用的是org.apache.struts.action. ActionServlet
12,Struts1.1框架使用RequestProcessor来处理真实的请求内容
13,后续就是调用相应的Action进行业务处理
14,注意,在第一次调用Request.getParameterValue("item")的时候,会进行转码操作,转码后相应的参数就是以Unicode的形式存在在jvm中,再根据需要可以传递各种形式的编码给客户端!(Unicode可以转换成任意字符集后,再输出[输出的其实是对应字符集的Byte数组])

调用RequestDispatcher.forward方法前后,对应的Request实现类不同,RequestDispatcher.forward前使用的是org.apache.catalina.connector.RequestFacade类而RequestDispatcher.forward后使用的是org.apache.catalina.core.ApplicationHttpRequest,他们内部在ParseParameter的时候, 用来解码的默认的编码逻辑不同,使用不同的协议时,影响乱码的因素不同! (request.getParameter和request.getParameterValues取值时,第一次请求需要解码!)

具体参考Tomcat源码分析--ServletRequest.getParameterValues内部分析,Request字符集&QueryStringEncoding
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics