1、Request URL 與 Servlet url-pattern匹配順序與關係html
當一個請求發送到servlet容器(服務器)的時候,容器先會將請求的url減去當前應用上下文的路徑,就是scheme://ip:port/context的 url做爲servlet的映射url,訪問的是http://localhost:8080/test/index.html,個人應用上下文(context)是test,容器會將http://localhost:8080/test去掉,剩下的/index.html部分拿來和servlet的url-pattern進行匹配。前端
1. 精確路徑匹配(徹底匹配)java
以」/」開始的,不包含通配符*(不以通配符結尾)的,例如:web
<servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/index.html</url-pattern> </servlet-mapping>
2. 最長路徑匹配(路徑匹配)spring
以」/」開始的,而且以通配符*結尾的(通配符只能在結尾,不能放中間。例如,/index/te*/index.html這樣的)tomcat
<servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/img/*</url-pattern> </servlet-mapping>
對於最長路徑匹配,老是會匹配路徑長的,例如,有2個servlet-mapping以下。(本地服務器)服務器
<servlet-mapping> <servlet-name>A</servlet-name> <url-pattern>/test/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>B</servlet-name> <url-pattern>/test/a/*</url-pattern> </servlet-mapping>
對於請求http://localhost/test/a雖然A和B都知足,可是servlet容器就會選擇B,由於B匹配到的長度更長。app
3. 擴展匹配jsp
以*.開始,以擴展名結束的,例如: 測試
<servlet-mapping> <servlet-name>spring-dispatcher-servlet</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping>
4. 默認servlet匹配
只有一個」/」,例如:
<servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
2、DispatcherServlet 的url-pattern
在說DispatcherServlet 的url-pattern以前得先介紹一個比較重要的點,就是咱們的項目下的WEB-INF中web.xml中的url-pattern是不容許重複的,例如同時在項目中配置以下2個相同默認的映射路徑,服務器啓動就會報錯。
<servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>spring-dispatcher-servlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
可能會有人有疑問,在tomcat服務器的web.xml中已經定義了以下圖所示的servlet的url-pattern,而在咱們本身的項目中的web.xml中定義一樣的默認servlet-mapping url-pattern爲何沒有報錯呢?
圖1 tomcat默認的Servlet
圖2 tomcat jsp Servlet
圖3 tomcat 默認的映射
對於這個問題尚未仔細研究過,不過應該是default servlet是單獨的最後處理的,想一下這個道理很簡單,只有咱們的web.xml中沒有找到映射纔會到default servlet因此不存在衝突的問題。
下載再來看DispatcherServlet中下面這2個servlet-mapping的區別
<servlet-mapping> <servlet-name>spring-dispatcher-servlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>spring-dispatcher-servlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
DispatcherServlet本質上仍是一個servlet,根據上面所介紹的servlet匹配順序和規則很容易得出」/*」是路徑匹配,只不過它是匹配全部路徑,就是隻有是頁面請求的不論是客戶端來的頁面請求仍是,服務器轉發的頁面請求都會被DispatcherServlet處理。
如今對於把DispatcherServlet的servlet-mapping配置爲」/*」出現的各類404錯誤就很是明顯了。DispatcherServlet處理請求是咱們本身實現的,可是全部請求(根據最長路徑匹配規則,除非有更加精確的匹配,例如,/view/*)都到了DispatcherServlet顯然咱們沒有實現的映射的部分就會出現404錯誤,例如各類靜態資源的請求等。
DispatcherServlet的servlet-mapping若是配置的是」/」,這個是個默認的servlet,就是在沒有找到匹配的servlet的時候就使用DispatcherServlet。這個一樣由於咱們使用SpringMVC一般值配置了DispatcherServlet,而沒有配置其餘的servlet,對於這種狀況」/」和」/*」相差不大。
不過有一點DispatcherServlet的servlet-mapping若是配置的是」/」則能夠訪問的<welcome-file-list>設置的頁面。而」/*」訪問不到,這個緣由尚未仔細研究。關於」/」和」/*」之間的差異在stackoverflow上有一個問題 」/」和」/*」 的差異 對於這個問題的有的回答剛剛開始看以爲很對,可是經過不斷的測試和更加深刻的思考也會發現一些問題,能夠參考測試一下,順便想想Servlet的匹配規則。
3、DispatcherServlet servlet-mapping配置策略參考
配置url-pattern的時候儘可能使用更加具體的模式,例如使用後綴匹配,例如,*.do,*.html,*.action等方式。
若是你以爲上面的方式不夠優雅,能夠把要按模塊設置前綴,例如,使用/user/*,/shop/*這樣的方式來處理。
對於靜態資源的映射能夠直接經過像下面的方式直接經過default Servlet來解決,這樣就避免過多的轉發,提升效率。
<servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/img/*</url-pattern> </servlet-mapping>
4、其餘一些問題
常常有一些404錯誤很難找到緣由,由於不少狀況能夠引發服務器返回404錯誤,我沒有讀過tomcat的源碼,因此很難知道根本緣由,不過對於使用SpringMVC若是出現了像下面這樣常見的錯誤。
No mapping found for HTTP request with URI [/context/xxx/xxx] in DispatcherServlet with name 'spring-dispatcher-servlet'
那麼就是servlet容器已經找到了DispatcherServlet可是DispatcherServlet沒有設置相應的映射的方法。
還有就是路徑前面帶不帶」/」的的區別,這裏可使用一個小技巧幫助記憶,就是服務器端(servlet,web.xml,RequestMapping等配置中)的路徑加上」/」表示的是相對於上下文環境(context),例如,
request.getRequestDispatcher("/index.html").forward(request, response);
假如是本地服務器,端口是8080項目上下文環境是test,那麼上面的就表示轉發到http://localhost:8080/test/index.html這個路徑。而在前端頁面(jsp中編譯也是這個原則)中的」/」則表示根路徑,例如,在jsp中有連接是」/index.html」表示的就是http://localhost:8080/index.html這個路徑。
對於沒有加上」/」的路徑都是相對路徑,就是當前文件所在目錄的路徑加上指定的連接。