Why request which start with “/WEB-INF” cannot be

2020-04-12 09:13发布

问题:

[context] tomcat 7 - java 1.7

Hey everyone; I'm facing with stranges working. In my web.xml file, I mapped request like this :

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 (implements 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 (extends HttpServlet)

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

[1 = Expected result] First, when I tried to request "/foo/bar", the filter and the servlet were called (and the page display the word 'foo'). Console result :

/foo/bar    
error

[2 = Unexpected result] Then, when I tried to request "/WEB-INF/foo/bar", nothing was called (my filter and my servlet were not hit) and I get a Tomcat error report :

HTTP Status 404 -

type Status report

message

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

EDIT : Here, I expected to get the following result :

/WEB-INF/foo/bar    
error

I aim to use my Filter to handle Exception ("/WEB-INF" calls included).

  • Why request which start with "/WEB-INF/" never hit filter/servlet mapped on "/*" pattern ?
  • How can we solve this problem?

Thanks in advance!

PS : I would like to keep my current web.xml configuration ("url-pattern" = "/*" ; without using "error-page")


EDIT : My question was misunderstood. I don't want to serve file access under my "WEB-INF" directory. I want to serve every request with my Filter and Servlet (url-pattern='/*') even if the request URI start with "/WEB-INF/". Thanks !

回答1:

There's a major conceptual misunderstanding here. Resources in /WEB-INF aren't publicly accessible at all. The way how you put the question indicates otherwise. This is not right. I believe that you just asked about the concrete problem the wrong way.

Based on a comment, I understood that you wanted to log accessed files in /WEB-INF as well as 404 errors. I guess that you actually meant that you want to log forwarded, included and error'ed resources as well next to directly requested resources. Normally, the forwarded and included resources are indeed hidden in /WEB-INF to prevent direct access.

A filter is by default invoked on directly requested resources only, not on forwarded and included resources nor on error'ed resources like in your 404 attempt. For that you need to add the appropriate <dispatcher> entries to the mapping:

<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>

(each of them are optional; the REQUEST is the default one when totally absent)

This way the filter will not only intercept on directly requested resources, but also on forwarded, included and error'ed resources. The ERROR dispatcher will make it to kick in on the 404 error as well.



回答2:

WEB-INF directory is a private area of the web application, any files under WEB-INF directory cannot be accessed directly from browser by specifying the URL like the way you've specified.

The web container will not serve the content of this directory. However the content of the this directory is accessible by the classes, like the servlets that you've mapped in your web.xml within the application.



回答3:

If you want to restrict direct URL access to some files, put them under WEB-INF directory.

Quote from here: http://www.servletworld.com/servlet-tutorials/web-application-directory-structure.html

WEB-INF directory is a private area of the web application, any files under WEB-INF directory cannot be accessed directly from browser by specifying the URL like http://somesite/WEB-INF/someresource.html. Web container will not serve the content of this directory. However the content of the WEB-INF directory is accessible by the classes within the application. So if there are any resources like JSPs or HTML document that you don’t wish to be accessible directly from web browser, you should place it under WEB-INF directory.



回答4:

Both answers posted are correct and this is the same for any application server you use and JDK. Although from servlet specification 3.0 web.xml is optional or you could use web-framgment.xml to break web.xml.



回答5:

According to the servlet specification, any requests from the client to access the resources in WEB-INF/ directory must be returned with a SC_NOT_FOUND(404) response. See section 10.5 Directory Structure.

https://download.oracle.com/otn-pub/jcp/servlet-3_1-fr-eval-spec/servlet-3_1-final.pdf https://download.oracle.com/otn-pub/jcp/servlet-3.0-fr-eval-oth-JSpec/servlet-3_0-final-spec.pdf