前言
似乎是很久以前就看到这篇文章了吧,, ” http://www.xuebuyuan.com/1287083.html “, 当时 也是直接了解了一下了一下自己的场景, 然后 解决了问题 就没有在管其中的一些细节了, 然后 今天似乎是突发奇想[哦 不对 似乎是在某群里看到了一个乱码问题], 就想走一走这个流程
——————————————————– refer ————————————————————
——————————————————– refer ————————————————————
直接贴原帖中的相关文字, 在ueditor中格式会变乱, 因此 这里直接贴截图吧
首先是走的第一个关于pathInfo的处理的流程,, 走完之后 发现了一些问题, 因此 分享一下, 这里没有什么其他意思, 仅仅是对于这个问题去看了一下相关的代码, 然后 写了一些关于自己的理解而已
因为个人水平有限, 因此 难免存在错误的地方, 因此 请大家多多指正
我这里环境为 : win7 + jdk1.7.40 + tomcat7.0.54
获取客户端请求的请求行的信息
AbstractHttp11Processor.process
InternalInputBuffer. parseRequestLine
请注意, 这里配置的是request.requestURI
在request中能够更新requestURI的方式只能够通过request.requestURI, 然后对获取到的MessageBytes进行操作, 现在 我们来看看操作了requestURI的地方有哪些
Request.requestURI
上图中 红色的部分为我们需要关注的方法, 一个是对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
这里的逻辑主要是格式化requestURI, 去掉”协议”, “主机”, “端口” 部分, 留下contextPath, pathInfo
1. “http://localhost:8080/HelloServlet/action/getPath.do?name=hx” -> “/HelloServlet/action/getPath.do?name=hx”
然后 之后是CoyoteAdapter. postParseRequest
注意这里的decodedURI是requestURI的一个副本, 因此后面的操作都和requestURI没有任何关系了
首先是url解码, 将”%23”形式的子字符串转义其字节表示, 其他的字符串不变
然后 是规则化decodedURI, 确保第一个字符为”/”, 将”//”替换为”/”, 将”/./”替换为”/” 等等, 具体请查看相关逻辑, 不合法返回400
然后 是convertURI, 也就是我们这里的重点了, 注意这里是转换的decodeURI
最后是校验decodedURI是否合法, 如果不合法返回400
因此 本帖想说的就是, pathInfo的解码 和server.xml中的Connector的URIEncoding配置无关
再来看一看request.decodedURI
Request.decoedURI
Request.getDecodedRequestURI
Request.getDecodedRequestURIMB
除了上面的CoyoteAdapter.postParseRequest, 之外 其他的三个操作均为只读操作, 而且request.getDecodedRequestURI相关api也没有”放出去” 因此 用户也不会获取到该数据
再来看一下 org.apache.catalina.connector.request.getRequestURI
获取的是requestURI
一个实际的例子
注意, 这里要实现中文映射是有条件的, 什么条件呢?
CoyoteAdapter.postParseRequest
看到了吗, 传入需要匹配的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技术内幕”[许宁波著]