前言

似乎是很久以前就看到这篇文章了吧,, ” http://www.xuebuyuan.com/1287083.html “, 当时 也是直接了解了一下了一下自己的场景, 然后 解决了问题 就没有在管其中的一些细节了, 然后 今天似乎是突发奇想[哦 不对 似乎是在某群里看到了一个乱码问题], 就想走一走这个流程

——————————————————– refer ————————————————————

12 Tomcat编码问题01 pathInfo部分_客户端


——————————————————– refer ————————————————————

直接贴原帖中的相关文字, 在ueditor中格式会变乱, 因此 这里直接贴截图吧

首先是走的第一个关于pathInfo的处理的流程,, 走完之后 发现了一些问题, 因此 分享一下, 这里没有什么其他意思, 仅仅是对于这个问题去看了一下相关的代码, 然后 写了一些关于自己的理解而已

因为个人水平有限, 因此 难免存在错误的地方, 因此 请大家多多指正

我这里环境为 : win7 + jdk1.7.40 + tomcat7.0.54

获取客户端请求的请求行的信息

AbstractHttp11Processor.process

12 Tomcat编码问题01 pathInfo部分_tomcat_02

InternalInputBuffer. parseRequestLine

12 Tomcat编码问题01 pathInfo部分_java_03

请注意, 这里配置的是request.requestURI

在request中能够更新requestURI的方式只能够通过request.requestURI, 然后对获取到的MessageBytes进行操作, 现在 我们来看看操作了requestURI的地方有哪些

Request.requestURI

12 Tomcat编码问题01 pathInfo部分_客户端_04

上图中 红色的部分为我们需要关注的方法, 一个是对requestURI进行解码, 另外一个是对requestURI进行去掉”protocol ://host:port”部分

绿色箭头标记的几处usage为对requestURI的只读操作, FormAuthenticator的逻辑我不了解, 其他的为ajp协议相关的Connector 以及InputBuffer, 另外一个为使用nio相关api创建连接的InputBuffer [三条”平行”的逻辑逻辑应该是相似的, 因此 我们这里分析InternalInputBuffer]

上面想说的意思是整个客户端发送request, 到服务端响应response的过程中, 更新requestURI[http-io这条流程]的地方有上面红色方框处的三个方法, 以及FormAuthenticator[这里不讨论]

因此 我们关注剩余的两个更新requestURI的方法吧

InternalInputBuffer.parseRequestLine之后走的逻辑是 AbstractHttp11Processor.prepareRequest

12 Tomcat编码问题01 pathInfo部分_客户端_05

这里的逻辑主要是格式化requestURI, 去掉”协议”, “主机”, “端口” 部分, 留下contextPath, pathInfo
1. “http://localhost:8080/HelloServlet/action/getPath.do?name=hx” -> “/HelloServlet/action/getPath.do?name=hx”

然后 之后是CoyoteAdapter. postParseRequest

12 Tomcat编码问题01 pathInfo部分_xml_06

注意这里的decodedURI是requestURI的一个副本, 因此后面的操作都和requestURI没有任何关系了

首先是url解码, 将”%23”形式的子字符串转义其字节表示, 其他的字符串不变

然后 是规则化decodedURI, 确保第一个字符为”/”, 将”//”替换为”/”, 将”/./”替换为”/” 等等, 具体请查看相关逻辑, 不合法返回400

然后 是convertURI, 也就是我们这里的重点了, 注意这里是转换的decodeURI

最后是校验decodedURI是否合法, 如果不合法返回400

因此 本帖想说的就是, pathInfo的解码 和server.xml中的Connector的URIEncoding配置无关


再来看一看request.decodedURI

Request.decoedURI

12 Tomcat编码问题01 pathInfo部分_xml_07


Request.getDecodedRequestURI

12 Tomcat编码问题01 pathInfo部分_客户端_08


Request.getDecodedRequestURIMB

12 Tomcat编码问题01 pathInfo部分_客户端_09

除了上面的CoyoteAdapter.postParseRequest, 之外 其他的三个操作均为只读操作, 而且request.getDecodedRequestURI相关api也没有”放出去” 因此 用户也不会获取到该数据


再来看一下 org.apache.catalina.connector.request.getRequestURI

12 Tomcat编码问题01 pathInfo部分_客户端_10

获取的是requestURI


一个实际的例子

12 Tomcat编码问题01 pathInfo部分_tomcat_11

注意, 这里要实现中文映射是有条件的, 什么条件呢?

CoyoteAdapter.postParseRequest

12 Tomcat编码问题01 pathInfo部分_tomcat_12

看到了吗, 传入需要匹配的uri是decodedURI, 也就是经过解码过的uri, 因此 需要配置server.xml的Connector的URIEncoding为”客户端的URL的path部分编码的方式”

页面发送get请求的时候浏览器对于URL的各个部分如何编码的可以参考一下这篇文章

然后 才能够匹配到对应的servlet, 才能执行相关的逻辑

结论就是 : 对于request.getContextPath tomcat并没有对其进行特殊的解码, 以默认的iso8859-1进行解码[MessageBytes.toString], tomcat对于url的映射, 使用了server.xml的Connector的URIEncoding来解码[默认 iso8859-1], 进而进行映射逻辑的匹配

参考
http://www.xuebuyuan.com/1287083.html

“深入分析Java Web技术内幕”[许宁波著]