- 1 問題描述
- 2 問題定位
- 3 排查結果
問題描述
優付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.css、http://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. 模棱兩可的;含混不清的;不明確的

附圖-檔案名/檔案目錄名所不允許出現的字符,其中包括斜杠字符

看一篇文章可能只需要十幾分鐘,但寫一篇文章少則需要兩個小時(內容編排,尋找理論支撐等等),感謝各位訂閱與閱讀!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/297995.html
標籤:其他
