为什么以“/WEB-INF”开头的请求不能映射到servlet/filter?

3

[context] tomcat 7 - java 1.7

大家好,我遇到了一些奇怪的问题。在我的web.xml文件中,我像这样映射请求:

web.xml

<web-app>
    <filter>
        <filter-name>filter</filter-name>
        <filter-class>demo.DemoFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <servlet>
        <servlet-name>Servlet</servlet-name>
        <servlet-class>demo.DemoServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>Servlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

DemoFilter.java(实现 Filter 接口)

@Override
public void doFilter( ServletRequest req, ServletResponse res, FilterChain chain )
        throws IOException, ServletException
{
    try
    {
        chain.doFilter(req, res);
    }
    catch ( Exception e )
    {
        System.err.println("error");
        ((HttpServletResponse) res).setContentType("text/html");
        ((HttpServletResponse) res).setStatus(HttpServletResponse.SC_NOT_FOUND);
        res.getWriter().write("foo");
    }
}

DemoServlet.java(继承自HttpServlet)

@Override
protected void doGet( HttpServletRequest req, HttpServletResponse resp )
        throws ServletException, IOException
{
    System.err.println(req.getRequestURI());
    throw new RuntimeException("ERROR");
}

[1 = 预期结果] 首先,当我尝试请求“/foo/bar”时,过滤器和Servlet被调用(页面显示单词“foo”)。控制台输出结果如下:

/foo/bar    
error

[2 = 意外结果] 然后,当我尝试请求“/WEB-INF/foo/bar”时,没有任何东西被调用(我的过滤器和我的servlet没有被命中),我收到了一个Tomcat错误报告:

HTTP Status 404 -

type Status report

message

description The requested resource is not available.
Apache Tomcat/7.0.30

编辑:在这里,我希望得到以下结果:

/WEB-INF/foo/bar    
error

我希望使用我的过滤器来处理异常(包括“/WEB-INF”调用)。
为什么以“/WEB-INF/”开头的请求从未命中“/*”模式映射的过滤器/Servlet?
我们如何解决这个问题?
谢谢!
PS:我想保留当前的web.xml配置(“url-pattern”=“/*”;不使用“error-page”)
编辑:
我的问题被误解了。我不想在我的“WEB-INF”目录下提供文件访问。我想使用我的过滤器和Servlet(url-pattern='/*')来服务于每个请求,即使请求URI以“/WEB-INF/”开头。谢谢!

1
因为这是 Servlet 规范中所说的。 - user207421
1
你为什么要请求 /WEB-INF/foo/bar?你打算放置什么需要这样访问的内容呢? - TheZuck
@TheZuck 要创建一个记录用户操作的过滤器,例如。 或者在我的情况下,将异常处理集中在一个过滤器中。 - Passage One
我现在明白你想做什么了,这是一个有趣的问题,然而,由于WEB-INF非常特殊,答案将非常具体且在我看来不那么有趣。使用您的常规过滤器服务其他所有内容,并捕获其他1000种人们尝试渗透您的站点的方式的黑客攻击。访问WEB-INF(及其伴侣META-INF)只能来自黑客攻击,因此我不会觉得有义务以优雅的方式回应。 - TheZuck
Tomcat 7 - Java 1.7 - 这是犯罪。没有人应该再运行 JDK 7。请升级。 - duffymo
5个回答

6
这里存在一个重大的概念误解。在 /WEB-INF 中的资源根本不是公开可访问的。你提出问题的方式表明了另一种情况。这是不正确的。我认为你只是错误地问了具体的问题
根据评论,我理解你想要记录 /WEB-INF 中访问的文件以及 404 错误。我猜测你实际上想要记录转发、包含和错误的资源,以及直接请求的资源。通常情况下,转发和包含的资源的确被隐藏在 /WEB-INF 中,以防止直接访问。
过滤器默认仅对直接请求的资源进行调用,而不对转发和包含的资源或错误的资源(例如你的 404 尝试)进行调用。为此,你需要添加适当的 <dispatcher> 条目到映射中:
<filter-mapping>
    <filter-name>filter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>

每个选项都是可选的;当完全缺少时,REQUEST 是默认选项。
这种方式不仅可以拦截直接请求的资源,还可以拦截转发、包含和错误的资源。ERROR 调度程序也将在 404 错误时触发它。

即使使用了这4个调度程序定义,当请求URI以“/WEB-INF/”开头时,我的过滤器仍未被调用 :( - Passage One
过滤器已经被调用了,这更可能是你方面的误解。如果出现错误,在doFilter()调用之后才能使用ERROR_REQUEST_URI属性。 - BalusC
@BalusC:我又试了一次,还是不行... 当我调用"localhost:8080/WEB-INF/foo"时,没有任何东西被调用。源代码 - Passage One
你的 web.xml 声明了哪个 Servlet 版本?Tomcat 7 是一个 Servlet 3.0 兼容的容器,但是你在问题中提到的 <web-app> 根声明是空的。这是真实的代码还是过于简化了? - BalusC
我将<web-app>版本添加到2.5以接受<dispatcher>定义。这是一个Maven项目的真实代码,我使用tomcat7:run运行它。 - Passage One

2

WEB-INF目录是Web应用程序的私有区域,任何在WEB-INF目录下的文件都不能通过直接指定URL的方式从浏览器访问。

Web容器不会提供此目录的内容。但是,该目录的内容可被应用程序中在web.xml中映射的类(如Servlet)访问。


2
虽然我同意你的答案(和informatik01的答案)是正确的,但我有一个疑问。如果你将http://myServer/myWebApp/WEB-INF/web.xml映射到(比如说)myWebApp\publicDirectory\fake-web.xml,那么你就遵守了限制,但你不需要使用WEB-INF来使URL无效。我认为这就是这里所说的,因为OP正在将该URL映射到一个servlet(而不是期望直接检索文件)。 - SJuan76
我想表达的是:规格说明中是否还有其他禁止此类URL的限制? - SJuan76
@PassageOne:当您使用此URL时,它是否会触发您的过滤器?如果是,则可以检索请求URI,从中替换“WEB-INF”,并执行重定向。这不是一种干净的方法,但您可能希望查看它是否有效。 - Sujay
@Sujay 过滤器和Servlet没有被触发。我收到了Tomcat错误的提示 :( - Passage One

2
如果您想限制某些文件的直接URL访问,请将它们放在WEB-INF目录下。
引用自这里:http://www.servletworld.com/servlet-tutorials/web-application-directory-structure.html WEB-INF目录是Web应用程序的私有区域,任何位于WEB-INF目录下的文件都不能通过指定URL(如http://somesite/WEB-INF/someresource.html)直接从浏览器访问。Web容器不会提供此目录的内容。但是,WEB-INF目录的内容可由应用程序中的类访问。因此,如果有任何不希望从Web浏览器直接访问的资源,您应该将其放在WEB-INF目录下。

我不想在我的“WEB-INF”目录下提供文件服务。即使这个URI以“WEB-INF”开头,我也想在“/*” URI上映射自定义servlet或过滤器。 - Passage One
1
刚刚尝试使用过滤器映射在/*上,是的 - 当尝试访问/WEB-INF时,只会出现404错误,并且过滤器不会触发。您希望过滤/WEB-INF访问尝试也相当奇特。但是也许@BalusC知道如何做到这一点,他是Java EE和相关技术中最有经验的人之一。我个人从未需要过这样的东西,抱歉啊。 - informatik01
1
感谢你的时间;至少你终于理解了我的问题 ;) - Passage One

0

0

两个回答都是正确的,无论你使用哪个应用服务器和JDK都是一样的。虽然从Servlet规范3.0开始,web.xml是可选的,或者你可以使用web-fragment.xml来替代web.xml。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接