分析DispatcherServlet拦截"/"造成静态文件404
2017-08-17 22:52
253 查看
今天在项目中访问静态文件一直404,后来在web.xml里面加入了这样一段代码,就能够访问了。
这里以html为例,如果需要多种静态资源类型,就需要配置多个以上。
为什么配置这个就能访问了呢?default是哪个servlet?为什么要使用这个servlet处理静态资源?我的脑海中产生这样一系列的问题。
总的来说,是因为配置了spring MVC的DispatcherServlet拦截“/”,为了实现REST风格,拦截了所有的请求,同时,静态文件也被拦截。 所以激活Tomcat的defaultServlet来处理静态文件。
我们接着刚刚的疑问继续探究。
先在项目里面找了default,没有找到。很好,百度吧!百度说这是他tomcat默认的serlvet,那这个servlet是干什么用的呢?我们已经知道它的一个用处了,就是处理静态资源。从这个网址可以看到官方文档里面对DefaultServlet的解释。http://tomcat.apache.org/tomcat-7.0-doc/default-servlet.html#what
1. What is the DefaultServlet?
DefaultServlet是用来处理静态资源,就像处理目录列表一样。
2. Where is it declared?
DefaultServlet是在$CATALINA_BASE/conf/web.xml里面做全局声明的,默认情况下是这样子的
3. What can I change?
DefaultServlet允许下面这些初始化参数
debug 这个参数对tomcat的开发者用处比较大,对我们而言用处不大。可选的值有0,1,11,1000.[0]
listings 如果没有设置欢迎页,那么当我们访问项目名时,会显示文件目录吗?这个参数的值是true或者false.[false].(这里我把值设置成了true,并且删除了欢迎文件,访问项目时,显示了文件目录
可以对比我的项目目录
)
欢迎文件也是servlet api的一部分。警告:包含很多实体的文件目录是非常珍贵的。大量的对大文件列表的请求,十分消耗服务器资源。
readmeFile 如果设置了显示文件列表,readme文件可能也会显示在列表里面。这个文件是插入的,它可能包含html.
globalXsltFile 如果你想定制你的文件目录,你可以使用XSL来转换。这个的值也是一个相对文件的名称($CATALINA_BASE/conf/ or $CATALINA_HOME/conf/),这个将会给所有的文件目录使用。但是这个可以被每一个context或者directory覆盖。具体的请看下面的contextXsltFile和localXsltFile.
contextXsltFile 你可以通过配置contextXsltFile来定制你的文件目录。但是一定要使用上下文的相对路径,并且是一.xsl或者.xslt为扩展名的文件(例如:/path/to/context.xslt)。这个会覆盖globalXsltFile的值. 如果配置的文件路径不存在,仍然会使用globalXsltFile的配置。如果默认的globalXsltFile文件也不存在,那会直接显示文件目录。
localXsltFile 你同样可以通过配置localXsltFile来定制你的文件目录。它一定是以.xsl或.xslt为扩展名的在目录列表里面的文件。并且这个配置能覆盖globalXsltFile和contextXsltFile的配置。如果配置的这个值找不到对应文件,就会使用contextXsltFile的配置,如果contextXsltFile也找不到,就会使用globalXsltFile的配置,如果都找不到,那么就会展示默认的文件目录。
input 当读取资源文件时,服务器写入缓冲区的大小,单位为bytes.[2048]
output 当写入资源文件时,服务器输出缓冲区大小,单位为bytes.[2048]
readonly 上下文是否是只读的,HTTP的命令,像PUT,DELETE这些是不是被拒绝的。[true]
fileEncoding 读取静态资源时的文件编码。[platform default]
sendfileSize 如果使用的连接器支持sendfile,这意味着以KB大小的小文件将会被使用。通常使用负数来禁止sendfile.[48]
useAcceptRanges 如果设置为true,当响应时请求头的Accept-Ranges将会被设置。[true]
showServerInfo 当展示文件列表是,服务器信息是否在响应时一起发送给客户端。[true]
4. How do I customize directory listings?
第三点中的globalXsltFile,localXsltFile,contextXsltFile这几个参数都是用来定制文件目录的,那么具体怎么定制呢?
我们可以重新定义一个Servlet来继承DefaultServlet,重写里面的方法,并在web.xml里面生命。就是说,tomcat开发人员假定我们是可以读到DefaultServlet的代码的,并且可以做适当的调整。如果我们无法读到DefaultServlet的代码,那这种方法就不适用了。
我们也可以使用localXsltFile和globalXsltFile来配置,DefaultServlet将会根据localXsltFile和globalXsltFile的配置找到xsl转换文件,创建并运行一个xml文件。localXsltFile优先级最高,然后是globalXsltFile,最后是默认的行为,格式如下:
如果设置type='dir',就不用设置size
Readme是一个CDATA,不由xml解析器解析
下面这个xsl文件示例,是mimics默认的tomcat行为:
5. How do I secure directory listings?
在每一个web项目里面使用web.xml.你可以去看servlet文档的安全模块。
以上,都是tomcat官网上关于DefaultServelt的说明,我们了解DefaultServelt使用方法,相关参数的配置。那么具体怎么来处理静态资源的呢?还是不知道。
直接来看代码吧。。。
我们可以看到DefaultServlet继承了HttpServlet,刚刚那些参数都是DefaultServlet里面的属性,并且在构造器里面设置了默认值。
那么文件拦截后,交到doGet(),doPost方法处理。我们来看下。。在doGet()里面调用了serveResource(request, response, true)方法。我看了一下这个方法,不是所有的代码都能看懂,但是大致就是获取请求地址,然后处理跳转响应页面。和我们普通的servlet差不多。
最后就是要把这个default的servlet配置到springMVC跳转器的前面,这样请求就会走DefaultServlet了。
以上便是我的理解,欢迎指教!!
<servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping>
这里以html为例,如果需要多种静态资源类型,就需要配置多个以上。
为什么配置这个就能访问了呢?default是哪个servlet?为什么要使用这个servlet处理静态资源?我的脑海中产生这样一系列的问题。
总的来说,是因为配置了spring MVC的DispatcherServlet拦截“/”,为了实现REST风格,拦截了所有的请求,同时,静态文件也被拦截。 所以激活Tomcat的defaultServlet来处理静态文件。
我们接着刚刚的疑问继续探究。
先在项目里面找了default,没有找到。很好,百度吧!百度说这是他tomcat默认的serlvet,那这个servlet是干什么用的呢?我们已经知道它的一个用处了,就是处理静态资源。从这个网址可以看到官方文档里面对DefaultServlet的解释。http://tomcat.apache.org/tomcat-7.0-doc/default-servlet.html#what
1. What is the DefaultServlet?
DefaultServlet是用来处理静态资源,就像处理目录列表一样。
2. Where is it declared?
DefaultServlet是在$CATALINA_BASE/conf/web.xml里面做全局声明的,默认情况下是这样子的
<servlet> <servlet-name>default</servlet-name> <servlet-class> org.apache.catalina.servlets.DefaultServlet </servlet-class> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>listings</param-name> <param-value>false</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> ... <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>所以通常情况下,DefaultServlet是在web项目启动时加载的,同时debug调试和文件目录都是禁用的。这里的listings是指文件目录,可是文件目录又是什么呢?别着急,我们继续往下看。
3. What can I change?
DefaultServlet允许下面这些初始化参数
debug 这个参数对tomcat的开发者用处比较大,对我们而言用处不大。可选的值有0,1,11,1000.[0]
listings 如果没有设置欢迎页,那么当我们访问项目名时,会显示文件目录吗?这个参数的值是true或者false.[false].(这里我把值设置成了true,并且删除了欢迎文件,访问项目时,显示了文件目录
可以对比我的项目目录
)
欢迎文件也是servlet api的一部分。警告:包含很多实体的文件目录是非常珍贵的。大量的对大文件列表的请求,十分消耗服务器资源。
readmeFile 如果设置了显示文件列表,readme文件可能也会显示在列表里面。这个文件是插入的,它可能包含html.
globalXsltFile 如果你想定制你的文件目录,你可以使用XSL来转换。这个的值也是一个相对文件的名称($CATALINA_BASE/conf/ or $CATALINA_HOME/conf/),这个将会给所有的文件目录使用。但是这个可以被每一个context或者directory覆盖。具体的请看下面的contextXsltFile和localXsltFile.
contextXsltFile 你可以通过配置contextXsltFile来定制你的文件目录。但是一定要使用上下文的相对路径,并且是一.xsl或者.xslt为扩展名的文件(例如:/path/to/context.xslt)。这个会覆盖globalXsltFile的值. 如果配置的文件路径不存在,仍然会使用globalXsltFile的配置。如果默认的globalXsltFile文件也不存在,那会直接显示文件目录。
localXsltFile 你同样可以通过配置localXsltFile来定制你的文件目录。它一定是以.xsl或.xslt为扩展名的在目录列表里面的文件。并且这个配置能覆盖globalXsltFile和contextXsltFile的配置。如果配置的这个值找不到对应文件,就会使用contextXsltFile的配置,如果contextXsltFile也找不到,就会使用globalXsltFile的配置,如果都找不到,那么就会展示默认的文件目录。
input 当读取资源文件时,服务器写入缓冲区的大小,单位为bytes.[2048]
output 当写入资源文件时,服务器输出缓冲区大小,单位为bytes.[2048]
readonly 上下文是否是只读的,HTTP的命令,像PUT,DELETE这些是不是被拒绝的。[true]
fileEncoding 读取静态资源时的文件编码。[platform default]
sendfileSize 如果使用的连接器支持sendfile,这意味着以KB大小的小文件将会被使用。通常使用负数来禁止sendfile.[48]
useAcceptRanges 如果设置为true,当响应时请求头的Accept-Ranges将会被设置。[true]
showServerInfo 当展示文件列表是,服务器信息是否在响应时一起发送给客户端。[true]
4. How do I customize directory listings?
第三点中的globalXsltFile,localXsltFile,contextXsltFile这几个参数都是用来定制文件目录的,那么具体怎么定制呢?
我们可以重新定义一个Servlet来继承DefaultServlet,重写里面的方法,并在web.xml里面生命。就是说,tomcat开发人员假定我们是可以读到DefaultServlet的代码的,并且可以做适当的调整。如果我们无法读到DefaultServlet的代码,那这种方法就不适用了。
我们也可以使用localXsltFile和globalXsltFile来配置,DefaultServlet将会根据localXsltFile和globalXsltFile的配置找到xsl转换文件,创建并运行一个xml文件。localXsltFile优先级最高,然后是globalXsltFile,最后是默认的行为,格式如下:
<listing> <entries> <entry type='file|dir' urlPath='aPath' size='###' date='gmt date'> fileName1 </entry> <entry type='file|dir' urlPath='aPath' size='###' date='gmt date'> fileName2 </entry> ... </entries> <readme></readme> </listing>
如果设置type='dir',就不用设置size
Readme是一个CDATA,不由xml解析器解析
下面这个xsl文件示例,是mimics默认的tomcat行为:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0"> <xsl:output method="html" html-version="5.0" encoding="UTF-8" indent="no" doctype-system="about:legacy-compat"/> <xsl:template match="listing"> <html> <head> <title> Sample Directory Listing For <xsl:value-of select="@directory"/> </title> <style> h1 {color : white;background-color : #0086b2;} h3 {color : white;background-color : #0086b2;} body {font-family : sans-serif,Arial,Tahoma; color : black;background-color : white;} b {color : white;background-color : #0086b2;} a {color : black;} HR{color : #0086b2;} table td { padding: 5px; } </style> </head> <body> <h1>Sample Directory Listing For <xsl:value-of select="@directory"/> </h1> <hr style="height: 1px;" /> <table style="width: 100%;"> <tr> <th style="text-align: left;">Filename</th> <th style="text-align: center;">Size</th> <th style="text-align: right;">Last Modified</th> </tr> <xsl:apply-templates select="entries"/> </table> <xsl:apply-templates select="readme"/> <hr style="height: 1px;" /> <h3>Apache Tomcat/8.0</h3> </body> </html> </xsl:template> <xsl:template match="entries"> <xsl:apply-templates select="entry"/> </xsl:template> <xsl:template match="readme"> <hr style="height: 1px;" /> <pre><xsl:apply-templates/></pre> </xsl:template> <xsl:template match="entry"> <tr> <td style="text-align: left;"> <xsl:variable name="urlPath" select="@urlPath"/> <a href="{$urlPath}"> <pre><xsl:apply-templates/></pre> </a> </td> <td style="text-align: right;"> <pre><xsl:value-of select="@size"/></pre> </td> <td style="text-align: right;"> <pre><xsl:value-of select="@date"/></pre> </td> </tr> </xsl:template> </xsl:stylesheet>
5. How do I secure directory listings?
在每一个web项目里面使用web.xml.你可以去看servlet文档的安全模块。
以上,都是tomcat官网上关于DefaultServelt的说明,我们了解DefaultServelt使用方法,相关参数的配置。那么具体怎么来处理静态资源的呢?还是不知道。
直接来看代码吧。。。
我们可以看到DefaultServlet继承了HttpServlet,刚刚那些参数都是DefaultServlet里面的属性,并且在构造器里面设置了默认值。
/* */ private static final long serialVersionUID = 1L; /* */ private static final DocumentBuilderFactory factory; /* */ private static final SecureEntityResolver secureEntityResolver; /* */ protected int debug; /* */ protected int input; /* */ protected boolean listings; /* */ protected boolean readOnly; /* */ protected int output; /* */ protected static final URLEncoder urlEncoder; /* */ protected String localXsltFile; /* */ protected String contextXsltFile; /* */ protected String globalXsltFile; /* */ protected String readmeFile; /* */ protected transient ProxyDirContext resources; /* */ protected String fileEncoding; /* */ protected int sendfileSize; /* */ protected boolean useAcceptRanges; /* 227 */ protected static final ArrayList<Range> FULL = new ArrayList(); /* */ protected boolean showServerInfo; /* */ protected static final String mimeSeparation = "CATALINA_MIME_BOUNDARY"; /* */ protected static final String RESOURCES_JNDI_NAME = "java:/comp/Resources"; /* */ protected static final StringManager sm; /* */ protected static final int BUFFER_SIZE = 4096; /* */ /* */ public DefaultServlet() /* */ { /* 144 */ this.debug = 0; /* */ /* 150 */ this.input = 2048; /* */ /* 156 */ this.listings = false; /* */ /* 162 */ this.readOnly = true; /* */ /* 168 */ this.output = 2048; /* */ /* 180 */ this.localXsltFile = null; /* */ /* 186 */ this.contextXsltFile = null; /* */ /* 192 */ this.globalXsltFile = null; /* */ /* 198 */ this.readmeFile = null; /* */ /* 204 */ this.resources = null; /* */ /* 211 */ this.fileEncoding = null; /* */ /* 217 */ this.sendfileSize = 49152; /* */ /* 222 */ this.useAcceptRanges = true; /* */ /* 232 */ this.showServerInfo = true; /* */ }接着就是destroy()和init()方法。init()在服务器启动时执行,destroy()方法在服务器停止时执行。在init()方法里面,我们可以看到它是去读取配置文件的这些属性值,并赋值。
/* */ public void init()/* */ throws ServletException /* */ { /* 305 */ if (getServletConfig().getInitParameter("debug") != null) { /* 306 */ this.debug = Integer.parseInt(getServletConfig().getInitParameter("debug")); /* */ } /* 308 */ if (getServletConfig().getInitParameter("input") != null) { /* 309 */ this.input = Integer.parseInt(getServletConfig().getInitParameter("input")); /* */ } /* 311 */ if (getServletConfig().getInitParameter("output") != null) { /* 312 */ this.output = Integer.parseInt(getServletConfig().getInitParameter("output")); /* */ } /* 314 */ this.listings = Boolean.parseBoolean(getServletConfig().getInitParameter("listings")); /* */ /* 316 */ if (getServletConfig().getInitParameter("readonly") != null) { /* 317 */ this.readOnly = Boolean.parseBoolean(getServletConfig().getInitParameter("readonly")); /* */ } /* 319 */ if (getServletConfig().getInitParameter("sendfileSize") != null) { /* 320 */ this.sendfileSize = (Integer.parseInt(getServletConfig().getInitParameter("sendfileSize")) * 1024); /* */ } /* */ /* 323 */ this.fileEncoding = getServletConfig().getInitParameter("fileEncoding"); /* */ /* 325 */ this.globalXsltFile = getServletConfig().getInitParameter("globalXsltFile"); /* 326 */ this.contextXsltFile = getServletConfig().getInitParameter("contextXsltFile"); /* 327 */ this.localXsltFile = getServletConfig().getInitParameter("localXsltFile"); /* 328 */ this.readmeFile = getServletConfig().getInitParameter("readmeFile"); /* */ /* 330 */ if (getServletConfig().getInitParameter("useAcceptRanges") != null) { /* 331 */ this.useAcceptRanges = Boolean .parseBoolean(getServletConfig().getInitParameter("useAcceptRanges")); /* */ } /* */ /* 334 */ if (this.input < 256) /* 335 */ this.input = 256; /* 336 */ if (this.output < 256) { /* 337 */ this.output = 256; /* */ } /* 339 */ if (this.debug > 0) { /* 340 */ log(new StringBuilder().append("DefaultServlet.init: input buffer size=").append(this.input) .append(", output buffer size=").append(this.output).toString()); /* */ } /* */ /* 345 */ this.resources = ((ProxyDirContext) getServletContext() .getAttribute("org.apache.catalina.resources")); /* */ /* 347 */ if (this.resources == null) { /* */ try { /* 349 */ this.resources = ((ProxyDirContext) new InitialContext().lookup("java:/comp/Resources")); /* */ } /* */ catch (NamingException e) /* */ { /* 354 */ throw new ServletException("No resources", e); /* */ } /* */ } /* */ /* 358 */ if (this.resources == null) { /* 359 */ throw new UnavailableException("No resources"); /* */ } /* */ /* 362 */ if (getServletConfig().getInitParameter("showServerInfo") != null) /* 363 */ this.showServerInfo = Boolean .parseBoolean(getServletConfig().getInitParameter("showServerInfo")); /* */ }我猜测getServletConfig().getInitParameter("debug")这两个方法就是读取在web.xml里面配置的default的参数的值的。
那么文件拦截后,交到doGet(),doPost方法处理。我们来看下。。在doGet()里面调用了serveResource(request, response, true)方法。我看了一下这个方法,不是所有的代码都能看懂,但是大致就是获取请求地址,然后处理跳转响应页面。和我们普通的servlet差不多。
最后就是要把这个default的servlet配置到springMVC跳转器的前面,这样请求就会走DefaultServlet了。
以上便是我的理解,欢迎指教!!
相关文章推荐
- SpringMVC项目中静态资源js,css文件访问不到404
- HTTP错误 404.17 - Not Found" IIS 7.5 请求的内容似乎是脚本,因而将无法由静态文件处理程序来处理
- Django-项目上线后,静态文件配置失效以及404、500页面的全局配置
- Android版本的"Wannacry"文件加密病毒样本分析(附带锁机)
- 对Oracle导出文件错误和DMP文件结构的分析,EXP-00008: 遇到 ORACLE 错误 904 ORA-00904: "MAXSIZE": invalid identifier
- nginx 静态文件 ajax post 404
- jsp的静态包含与动态包含:<%@ include file="" %>和<jsp:include page=""></jsp:include>区别与分析
- springMVC访问静态资源:为什么图片/js/css等文件写在jsp中是404不能获取
- HTTP错误 404.17 - Not Found" IIS 7.5 请求的内容似乎是脚本,因而将无法由静态文件处理程序来处理
- 报表定义文件出现 xmlns="" 造成报表无法解析怎么办?
- SpringMVC处理静态文件源码分析
- django设置debug设为False静态文件404
- SpringMVC处理静态文件源码分析
- 简单粗暴的对android so文件加壳,防止静态分析
- 正常访问静态文件,不要找不到静态文件报404
- 部署在服务器上的应用请求json文件返回404解决方法及原因分析
- 谈PHP生成静态页面分析 模板+缓存+写文件
- vSphere Client提示分析"clients.xml"文件出错
- Android版本的"Wannacry"文件加密病毒样本分析(附带锁机)
- (springmvc)页面找不到静态资源文件Failed to load resource: the server responded with a status of 404 (Not Found)