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这个路径。
对于没有加上”/”的路径都是相对路径,就是当前文件所在目录的路径加上指定的连接。