【问题标题】:Tomcat filter in web.xml gets triggered when sending OPTIONS from Postman but not when sending OPTIONS from browser or curl [closed]从 Postman 发送选项时会触发 web.xml 中的 Tomcat 过滤器,但从浏览器或 curl 发送选项时不会触发 [关闭]
【发布时间】:2020-04-27 02:39:03
【问题描述】:

Tomcat(托管我的 java 后端 API)有这个过滤器:

<filter>
    <filter-name>ApiOriginFilter</filter-name>
    <filter-class>io.swagger.api.ApiOriginFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>ApiOriginFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

这是这个java代码(我添加了 System.out.println("Test"); 部分):

package io.swagger.api;

import java.io.IOException;

import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;

@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2020-01-07T08:47:08.031Z[GMT]")public class ApiOriginFilter implements javax.servlet.Filter {
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        HttpServletResponse res = (HttpServletResponse) response;
        res.addHeader("Access-Control-Allow-Origin", "*");
        res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
        res.addHeader("Access-Control-Allow-Headers", "Content-Type");
        chain.doFilter(request, response);
        System.out.println("Test");
    }

    public void destroy() {}

    public void init(FilterConfig filterConfig) throws ServletException {}
}

我正在构建一个 Ionic/React/Typescript 应用程序,它执行以下 API 调用 Java API:

const apiClient = axios.create({
    baseURL: 'http://10.0.29.1:8080/swagger-jaxrs-server.1.0.0/v1/',
    responseType: 'json',
    headers: {
      'Content-Type': 'application/json',
      'Access-Control-Allow-Origin' : '*'
    }
});
const createUser = async (newUser: NewUser) => {
  try {
    const response = await apiClient.post<User>('/users', newUser);
    const user = response.data;
    return user;
  } catch (err) {
    if (err && err.response) {
      const axiosError = err as AxiosError<ServerError>
      if (axiosError.response)
      {
        return axiosError.response.data;
      }
      else
      {
        return 0;
      }
    }

它只是发布到“http://10.0.29.1:8080/swagger-jaxrs-server.1.0.0/v1/users”。在 Chrome 和 Firefox 中执行此调用时,我收到以下响应:

Chrome OPTIONS 响应 Firefox 选项响应

两个浏览器当然都抱怨 CORS(OPTIONS 响应标头中没有 Access-Control-Allow-Origin):

Firefox CORS 警告 Chrome CORS 警告

当我在 POSTMAN 中做同样的事情时:

它有效。

转到/opt/tomcat/logs/catalina.out 我明白了:

“测试”行来自我从邮递员发帖时。它是 System.out.println("Test");我在 ApiOriginFilter.java 函数中添加的代码。表示当 Postman 发送 OPTIONS 时会触发过滤器。浏览器发生了什么?这个响应来自哪里,为什么没有触发过滤器?

更新:如果我复制并粘贴 Firefox/Chrome 与 OPTIONS 请求一起发送给 Postman 的标头,Postman 仍然可以工作。如果我将 Postman 标头复制到 headers.txt 文件中:

User-Agent: PostmanRuntime/7.21.0
Accept: */*
Cache-Control: no-cache
Postman-Token: b3b6ae69-58fe-44dc-bdf0-7280679f0f32
Host: 10.0.29.1:8080
Accept-Encoding: gzip, deflate
Content-Length: 0
Connection: keep-alive

然后执行 curl -H @headers.txt -i -X OPTIONS http://10.0.29.1:8080/swagger-jaxrs-server.1.0.0/v1/users 它响应

HTTP/1.1 200
Allow: OPTIONS, GET, HEAD, POST
Content-Length: 0
Date: Fri, 10 Jan 2020 06:47:45 GMT
Keep-Alive: timeout=20
Connection: keep-alive

这意味着过滤器没有被调用。如果我只是 curl -i -X OPTIONS http://10.0.29.1:8080/swagger-jaxrs-server.1.0.0/v1/users 它会响应

HTTP/1.1 200
Allow: OPTIONS, GET, HEAD, POST
Content-Length: 0
Date: Fri, 10 Jan 2020 06:51:37 GMT

仍然没有调用过滤器。

【问题讨论】:

  • 与浏览器发送的内容相比,您的 Postman 请求是否在属性方面有所不同?一般建议是保持它们完全相同。
  • 我同意,但我不控制浏览器的 OPTIONS 调用,它由浏览器自动完成
  • 但你确实控制着你的邮递员。
  • 我将 Firefox/Chrome 的所有标题复制并粘贴到 Postman 并发送了请求,但 Postman 仍然可以使用
  • 不确定是否相关,但您的 Typescript 是否在 URL 中添加了两个斜杠?像“//用户”。另外,尝试将@WebFilter(urlPatterns = {"/*"}) 添加到您的过滤器中。

标签: java tomcat cors


【解决方案1】:

这是其中一种拼写错误会让您想好几个小时的情况。如果您注意到,Postman 中的 URL 是 http://10.0.29.1:8080/swagger-jaxrs-server-1.0.0/v1/,而在源代码中它是 http://10.0.29.1:8080/swagger-jaxrs-server.1.0.0/v1/server1 之间的 . 字符是错误的,它应该是 -。我还在 cURL 中使用了错误的地址,因为我是从源代码中复制它的。在某些时候,我什至有两个(对我而言)相同的 Postman OPTIONS 请求,一个有效,一个无效(!)。

这是我让自己注意到它的方式:

首先,我将 RequestDumperFilter(Tomcat 7 或更高版本)添加到我的 webapp 的 web.xml 文件(位于 /opt/tomcat/webapps/&lt;your-webapp&gt;/WEB-INF/web.xml,以便捕获所有 HTTP 标头(请求/响应),如下所示

<filter>
    <filter-name>requestdumper</filter-name>
    <filter-class>
        org.apache.catalina.filters.RequestDumperFilter
    </filter-class>
</filter>
<filter-mapping>
    <filter-name>requestdumper</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

/opt/tomcat/conf/logging.properties 文件中,我为过滤器添加了一个日志处理程序,如下所示:

handlers = ..., 5request-dumper.org.apache.juli.FileHandler
...
5request-dumper.org.apache.juli.FileHandler.level = FINEST
5request-dumper.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
5request-dumper.org.apache.juli.FileHandler.prefix = request-dumper.
5request-dumper.org.apache.juli.FileHandler.formatter = org.apache.juli.VerbatimFormatter
org.apache.catalina.filters.RequestDumperFilter.level = INFO
org.apache.catalina.filters.RequestDumperFilter.handlers = 5request-dumper.org.apache.juli.FileHandler

信用:https://stackoverflow.com/a/8727615/1238675

但是在sudo service tomcat restart 之后,过滤器根本没有捕获错误的浏览器/curl 请求。然后我将过滤器放在/opt/tomcat/conf/web.xml 中,这样它就可以捕获对Tomcat 的任何请求,而不仅仅是我的webapp。实际上,我开始捕获标头,并将 Postman 引起的日志和浏览器引起的日志并排放置:

可以注意到左侧的contextPathpathInfoservletPath都是错误的。这让我立即(最终)查看了该 URL,然后就知道了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-06
    • 2023-04-11
    • 1970-01-01
    • 2012-05-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多