buguge - Keep it simple,stupid

知识就是力量,但更重要的,是运用知识的能力why buguge?

导航

IDEA中用jetty启动web项目时,url路径包含双斜杠会返回404 (url里多了一个斜杠/, jetty返回404,tomcat正常)

问题描述

优付OMS站点,本地在IDEA里用jetty9.4.*启动程序时,浏览器访问效果如下,页面错乱。

而把程序部署到测试环境是可以正常显示的。测试环境的web服务器是tomcat。

然后,本地用tomcat来启动程序,发现在浏览器里也是可以正常访问的。

 

 

 

经排查,点击左侧导航菜单打开功能页是如下这样实现的。可以看到,路径上存在双斜杠//,即比正常路径多了一个斜杠/。

 

 

同样的代码,为什么tomcat正常,而jetty却不正常呢?

 

问题定位

我们接下来直接基于这个功能页的url来排查。首先,不带双斜杠的url(http://localhost:8080/PCBossMgr/soho/showSaleInfoPage.html)在jetty或tomcat下都是ok的。所以,我们的关注点聚焦在带双斜杠的url(http://localhost:8080/PCBossMgr//soho/showSaleInfoPage.html)上。

本地服务器为jetty9.4.*时,浏览器网络请求如下。其中,Network里第一个请求http://localhost:8080/PCBossMgr//soho/showSaleInfoPage.html请求的是spring web controller的action方法,正常返回200;而之后的静态文件,如css、js,则返回了404。从请求地址 http://localhost:8080/PCBossMgr//layui/css/index.csshttp://localhost:8080/PCBossMgr//layui/layui.js里可以看到,这些url也是多了一个/,却无法正常访问。

 

 

 

再看tomcat的网络请求,无论是请求后台的action,还是静态的css、js资源文件,都是200。

 

 

 

静态资源url里多了斜杠"/",为什么用tomcat可以正常访问,而用jetty却404呢?

看来,tomcat与jetty两个web容器对url的处理方式不同。

 

排查结果

我找来最有技术灵性的小王杰同学一起排查原因。如下是最终的分析结果。

URI的RFC3986规范里,对请求路径(https://datatracker.ietf.org/doc/html/rfc3986#section-3.3,章节3.3 Path)有如下说明:

If a URI contains an authority component, then the path component must either be empty or begin with a slash ("/") character. If a URI does not contain an authority component, then the path cannot begin with two slash characters ("//"). In addition, a URI reference (Section 4.1) may be a relative-path reference, in which case the first path segment cannot contain a colon (":") character. The ABNF requires five separate rules to disambiguate these cases, only one of which will match the path substring within a given URI reference. We use the generic term "path component" to describe the URI substring matched by the parser to one of these rules.

翻译为:
如果URI包含权限组件,则路径组件必须为空或以斜杠(“/”)字符开头。如果URI不包含授权组件,则路径不能以两个斜杠字符(“/”)开头。此外,URI引用(第4.1节)可以是相对路径引用,在这种情况下,第一个路径段不能包含冒号(“:”)字符。ABNF需要五个独立的规则来消除这些情况的歧义,其中只有一个规则将匹配给定URI引用中的路径子字符串。我们使用通用术语“路径组件”来描述由解析器匹配到这些规则之一的URI子字符串。

就是说,

通常情况下,RFC3986规范不允许url路径里包含两个斜杠“//”。

 

在stackoverflow社区发现这么一篇帖子,Is a URL with // in the path-section valid? 文末回帖堪称精辟:yes, it is valid, no, don't use it.

 

再来说jetty,jetty严格遵守了RFC3986规范。也就是说,jetty不允许url里带两个斜杠,它会认为带有//的url是模棱两可的路径(ambiguous empty segment)。怎么讲?假如controller的action方法映射的路径有xxx/{var}/someurl,web静态目录里也有xxx/somedir/somefile,那么,当你访问url包含xxx//x的时候,jetty无法做出选择。所以,jetty直接来了个痛快的,不支持这种形式的url,以免造成歧义。

tomcat呢,tomcat “违背规范” ,tomcat直接把请求路径里包含的多个连续的斜杠替换成单个的斜杠,比如 xxx//someurl 会被替换为 xxx/someurl。况且实际在我们的web系统中,也难免会出现一些带有双斜杠的url。tomcat兼容了这种情况还是比较得民心的。

 

附图-tomcat替换多个斜杠为一个斜杠

 

 

附图-jetty中Violation枚举,罗列了URI路径中存在的各种“禁忌”,其中就有本文遇到的双斜杠问题。

violation 英 [ˌvaɪə'leɪʃ(ə)n] 美 [ˌvaɪə'leɪʃ(ə)n] n. 违反;违法;违章;越轨;侵犯;破坏;违例;犯规
ambiguous 英 [æmˈbɪɡjuəs] 美 [æmˈbɪɡjuəs] adj. 模棱两可的;含混不清的;不明确的

附图-文件名/文件目录名所不允许出现的字符,其中包括斜杠字符

 

 

看一篇文章可能只需要十几分钟,但写一篇文章少则需要两个小时(内容编排,寻找理论支撑等等),感谢各位订阅与阅读!

posted on 2021-09-06 22:00  buguge  阅读(1515)  评论(0编辑  收藏  举报