tomcat的缺省servlet如何处理静态资源

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了tomcat的缺省servlet如何处理静态资源相关的知识,希望对你有一定的参考价值。

参考技术A Tomcat的默认servlet,即org.apache.catalina.servlets.DefaultServlet,处理静态资源(例如html、CSS、javascript文件和图像等)的方法与标准的Web服务器类似。当请求一个静态资源时,因为没有映射到其他servlet或JSP文件,Tomcat将自动将该请求交给默认servlet来处理。

默认servlet会首先检查请求路径是否与Web应用程序上下文路径匹配。如果是,则该servlet将从磁盘上的Web应用程序目录中找到与请求路径对应的资源文件,并将其发送回客户端。如果请求路径与Web应用程序上下文路径不匹配,则默认servlet会将请求传递给上一个servlet(可能是前一个过滤器),以便进行进一步处理。

默认情况下,Tomcat使用默认servlet来提供Web应用程序中的静态内容。但是,也可以配置Tomcat以使用外部Web服务器(如Apache)来提供静态内容,这通常比使用默认servlet提供更高的性能和安全性。

总之,Tomcat的默认servlet可以方便的处理静态资源,并与标准的Web服务器类似。
参考技术B 我们都知道Web服务器与Web容器的区别。而且Tomcat是一种Web Container,与nginx/Apache这一类的Web Server本质区别是,Tomcat不光可以处理静态资源,还能处理Servlet文件。

响应Servlet文件这件事,我们虽然还没有深入分析,但多少有点司空见惯的感觉了,毕竟做为一个Servlet规范的参考实现,能处理Servlet自然是情理之中的。

那Tomcat又是如何处理静态资源的呢?

可能你习惯性的打开Tomcat,部署了一个应用之后,就开始查看其运行结果,或者更多的关注Servlet内的逻辑是否正确。至于静态资源处理这个事,可能不曾留意过。

那我们一起来看看,它究竟是怎么处理的。

本质上讲,Tomcat对于所有的静态资源,会做统一处理。也就是在所有你没有配置URL匹配的地方,Tomcat这个全局统一处理的配置就开始接管工作了。

这时,你不禁要问,这个东西我没有配置,它怎么生效的呢?

看这里!

在Tomcat的conf目录下,就是有全局配置文件server.xml在同一个目录下,有一个web.xml,打开它之后,你会发现这样的说明:

The default servlet for all web applications, that serves static
resources. It processes all requests that are not mapped to other

servlets with servlet mappings.

再向下,你会看到关于这个全局处理的Servlet声明,如下图

它的名字叫DefaultServlet

此处,它还有一个名为listings的初始化参数,默认值为false。这个参数主要作用,是在没有welcome文件时,控制应用目录内的文件是否允许列表显示。如果设置为true,就会常见的FTP服务器一样,把应用目录下的文件都列了出来,像下面这个样子。当然,这个样式也是可以自已定义的。

这个DefaultServlet的servlet-mapping是这样配置的

你会不会问,既然url-pattern配置的是 / ,那不就应该响应所有的请求了么?

对,我们上面说明中也提到了,是匹配所有你没定义的Servlet-mapping的请求。

而之所以自己定义的Servlet可以优先生效,则是因为Tomcat内的Servlet配置,是严格按照声明顺序初始化,并按此顺序响应请求,一层层按此比对,有一个可以响应请求,就用其处理。

下面又到了看源码的时间了,我们来看DefaultServlet中,静态资源响应处理。

文件位于org.apache.catalina.servlets.DefaultServlet文件中。

首先是这个文件,一般资源请求,都会走GET方法。

protected void doGet(HttpServletRequest request,

HttpServletResponse response)

throws IOException, ServletException

// Serve the requested resource, including the data content

serveResource(request, response, true, fileEncoding);



serveResource这个方法内容较多,放在这里查看不太方便。大致总结下,首先会判断要请求的资源是否存在,文件是否可读,之后,根据资源的类型,设置响应头的content-type,判断文件的时间,设置超时时间等,最终是流的读写。

整个应用内的资源存放在resources这个变量内,声明如下:

/**

* The complete set of web application resources

*/

protected transient WebResourceRoot resources = null;

这块和上面内容有关联的地方是,读取文件的时候,会判断请求的路径对应的资源是否为一个文件夹,如果是目录,就会判断listings这个参数,为true时才会列出内容,否则直接返回内容找不到,即404。代码是下面这个样子。

if (resource.isDirectory())

// Skip directory listings if we have been configured to

// suppress them

if (!listings)

response.sendError(HttpServletResponse.SC_NOT_FOUND,

request.getRequestURI());

return;

参考技术C 1 缺省servlet可以处理静态资源
2 当请求的资源为静态资源时,缺省servlet会首先检查请求的资源是否存在于web应用程序的根目录或者WEB-INF目录下,如果存在则直接返回该资源;如果不存在,则会将请求转发给下一个servlet或者JSP处理。

3 如果需要更高效的处理静态资源,可以使用专门的静态资源处理器,如Apache Httpd服务器或者Nginx服务器。

如何处理从 servlet 中的 Angular 应用程序发送的预检请求?

【中文标题】如何处理从 servlet 中的 Angular 应用程序发送的预检请求?【英文标题】:How to handle the preflight request send from an angular application in your servlet? 【发布时间】:2020-09-07 23:03:36 【问题描述】:

我正在 Angular 中创建一个项目,该项目从 localhost:8080 上运行的 tomcat 应用程序获取用户的 json。现在我正在尝试使用 http.put 更新用户。当我发送我的 put 请求时,我在控制台中打印了这个错误:

从源“http://localhost:4200”访问“http://localhost:8080/Servlet?command=UpdateUser”处的 XMLHttpRequest 已被 CORS 策略阻止:对预检请求的响应未通过访问控制检查:没有“Access-Control-Allow-Origin”标头出现在请求的资源上。

我的 servlet 使用了一个 handlerfactory,它使正确的处理程序来处理请求。 UpdateUser 处理程序现在有这个代码:

public class UpdateUser extends RequestHandler 
    @Override
    public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
        Enumeration<String> params = request.getParameterNames();
        System.out.println(params);
        while (params.hasMoreElements()) 
            String paramName = params.nextElement();
            System.out.println(paramName + ":" + request.getParameter(paramName));
        
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "X-PINGOTHER,Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization");
        response.addHeader("Access-Control-Expose-Headers", "xsrf-token");
        response.setStatus(HttpServletResponse.SC_ACCEPTED);
    

注意:我只是将 while 循环放在那里,这样我就可以看到我的 Angular 应用程序中的内容是如何到达我的处理程序的。

在我的 Angular 应用程序的 app.component.ts 中,我有这段代码来更新用户:

updateUser(user): void 
    this.userService.updateUser(user).subscribe();
  

这会在我的 user.service.ts 中调用这个方法:

  private httpOptions = headers: new HttpHeaders(
      'Content-Type':  'application/json'
  );
  updateUser(user): Observable<User> 
    return this.http.put<User>(this.updateUsersUrl, user, this.httpOptions);
  

在控制台的网络选项卡中,我看到我的处理程序被调用,但没有打印任何内容。 所以我想我可能需要在其他地方处理我的预检请求?

【问题讨论】:

这是一个 CORS 问题。浏览器在执行实际请求之前执行 OPTIONS 请求。确保您的 APi 响应 OPTIONS 请求的有效 CORS 标头。 我不是已经通过在我的处理程序中设置所有这些标头来做到这一点吗?还是我误会了? 我可以看到它的样子,但它似乎不起作用:-)。尝试使用 Postman 或其他工具在localhost:8080/Servlet?command=UpdateUser 触发 OPTIONS 请求,并查看 CORS 标头是否存在.. 哦,我完全忘记了尝试使用邮递员,谢谢!我收到的标题是:“ALLOW GET,HEAD,POST,OPTIONS”、“CONTENT-LENGTH 0”和一个日期。我在代码中设置的其他标题似乎没有出现... 我只是尝试发送一个 HEAD 请求,然后我得到了所有的标头 【参考方案1】:

在我的 servlet 中覆盖 doOptions 方法并在那里设置所有标题,似乎可以解决问题

【讨论】:

以上是关于tomcat的缺省servlet如何处理静态资源的主要内容,如果未能解决你的问题,请参考以下文章

phpcms静态路径 如何处理

Servlet容器如何处理请求资源路径

一个简单的Web服务器-支持Servlet请求

如何处理从 servlet 中的 Angular 应用程序发送的预检请求?

如何处理 Nginx 内部请求

Tomcat与Servlet