昨天配置了一下Dexcoder的404,500等错误页面,但是配置好项目发到服务器之后,不经意间发现session拦截器居然失效了,连后台都可以不用登录就进去了,这绝对是致命bug啊,赶紧排查。
一般我们实现的session拦截器,都是通过ServletPath来判断访问的路径是否需要session,典型的代码如下:
String servletPath = request.getServletPath(); if (StringUtils.startsWith(servletPath, "/admin")) { //... }
但是这些代码我并没有做过任何改动,那到底是什么原因导致了这个问题呢?
最后发现,居然是web.xml是的servlet-mapping
配置引起的,不同的url-pattern
配置会使request.getServletPath()
的返回值不同。
一开始我的spring mvc配置如下:
<servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>*</url-pattern> </servlet-mapping>
使用了*
,用如下测试代码:
System.out.println("ServletPath:" + request.getServletPath()); System.out.println("ContextPath:" + request.getContextPath()); System.out.println("RequestURI:" + request.getRequestURI()); System.out.println("PathInfo:" + request.getPathInfo()); System.out.println("RequestURL:" + request.getRequestURL());
在浏览器中访问http://localhost:8080/dexcoder/blog/article/1479
,发布到服务器上时因为直接绑定域名,一般都是没有项目名的,这里为了看的清晰,设置了项目名为dexcoder
。
输出如下:
ServletPath:/blog/article/1479
ContextPath:/dexcoder
RequestURI:/dexcoder/blog/article/1479
PathInfo:null
无疑/blog/article/1479
是我们所需要的,没有问题。
ps:当没有项目名时,ServletPath
和RequestURI
会一样。
因为有时候不光要用到页面访问的后缀,还会用到譬如.json
,.xml
等,因此我们把spring mvc的servlet-mapping改成:
<servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>
还是上面的测试代码,输出如下:
ServletPath:
ContextPath:/dexcoder
RequestURI:/dexcoder/blog/article/1479
PathInfo:/blog/article/1479
ServletPath为空了,相反PathInfo却有值了,这就是导致我们上面问题的根本原因,看来对servlet还是不够了解啊,做一笔糊涂账了。
怎么样来保证每次获取的都是我们想要的,不会随着web.xml是的配置变化受到影响呢?
有了上面的实例,实现起来也很简单,可以使用如下代码:
String servletPath = request.getServletPath(); String pathInfo = request.getPathInfo(); if (StringUtils.length(pathInfo) > 0) { servletPath = servletPath + pathInfo; }
或者下面的代码,效果都是一样的:
String uri = request.getRequestURI(); String contextPath = request.getContextPath(); if (StringUtils.length(contextPath) > 0) { uri = StringUtils.substring(uri, contextPath.length()); }