Tomcat CORS:预检成功,但实际请求失败,403 被禁止

Posted

技术标签:

【中文标题】Tomcat CORS:预检成功,但实际请求失败,403 被禁止【英文标题】:Tomcat CORS: Preflight successful, but actual request fails with 403 forbidden 【发布时间】:2015-12-24 07:40:06 【问题描述】:

我的 REST 服务部署在 Tomcat 7.0.64 (http://localhost:8080/xxx) 下。我使用由 html 页面提供的 javascript 库调用这些服务。这些 HTML 页面是从另一个来源 (http://localhost:9090/html/yyy.html) 提供的。

为了启用跨源请求,在服务器上,我在 web.xml 中配置了 CORSFilter,如下所示:

<filter>
    <filter-name>CorsFilter</filter-name>
    <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
    <init-param>
        <param-name>cors.allowed.origins</param-name>
        <param-value>*</param-value>
    </init-param>
    <init-param>
        <param-name>cors.allowed.methods</param-name>
        <param-value>GET,POST,HEAD,OPTIONS,PUT,PATCH,DELETE</param-value>
    </init-param>
    <init-param>
        <param-name>cors.allowed.headers</param-name>
        <param-value>Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,X-CUSTOM1,X-CUSOM2,X-CUSTOM3</param-value>
    </init-param>
    <init-param>
        <param-name>cors.exposed.headers</param-name>
        <param-value>Access-Control-Allow-Origin,Access-Control-Allow-Credentials,X-CUSTOM3</param-value>
    </init-param>
    <init-param>
        <param-name>cors.support.credentials</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
        <param-name>cors.preflight.maxage</param-name>
        <param-value>10</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CorsFilter</filter-name>
    <url-pattern>*</url-pattern>
</filter-mapping>

从 RequestDumper 的以下输出中,您可以注意到来自浏览器的预检请求已收到成功的响应 (200)。但是,随后的实际请求以 403 Forbidden 失败:

预检请求和响应

http-apr-8080-exec-6 ===============================================================
http-apr-8080-exec-8 START TIME        =26-Sep-2015 21:28:53
http-apr-8080-exec-8         requestURI=/xxxx/zzzz
http-apr-8080-exec-8           authType=null
http-apr-8080-exec-8  characterEncoding=null
http-apr-8080-exec-8      contentLength=-1
http-apr-8080-exec-8        contentType=null
http-apr-8080-exec-8        contextPath=/xxxx
http-apr-8080-exec-8             header=host=localhost:8080
http-apr-8080-exec-8             header=connection=keep-alive
http-apr-8080-exec-8             header=pragma=no-cache
http-apr-8080-exec-8             header=cache-control=no-cache
http-apr-8080-exec-8             header=access-control-request-method=POST
http-apr-8080-exec-8             header=origin=http://localhost:9090
http-apr-8080-exec-8             header=user-agent=Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.42 Safari/537.36
http-apr-8080-exec-8             header=access-control-request-headers=x-custom1, x-custom2
http-apr-8080-exec-8             header=accept=*/*
http-apr-8080-exec-8             header=referer=http://localhost:9090/html/yyyy.html
http-apr-8080-exec-8             header=accept-encoding=gzip, deflate, sdch
http-apr-8080-exec-8             header=accept-language=en-US,en;q=0.8,ta;q=0.6
http-apr-8080-exec-8             locale=en_US
http-apr-8080-exec-8             method=OPTIONS
http-apr-8080-exec-8           pathInfo=null
http-apr-8080-exec-8           protocol=HTTP/1.1
http-apr-8080-exec-8        queryString=null
http-apr-8080-exec-8         remoteAddr=127.0.0.1
http-apr-8080-exec-8         remoteHost=127.0.0.1
http-apr-8080-exec-8         remoteUser=null
http-apr-8080-exec-8 requestedSessionId=null
http-apr-8080-exec-8             scheme=http
http-apr-8080-exec-8         serverName=localhost
http-apr-8080-exec-8         serverPort=8080
http-apr-8080-exec-8        servletPath=/zzzz
http-apr-8080-exec-8           isSecure=false
http-apr-8080-exec-8 ------------------=--------------------------------------------
http-apr-8080-exec-8 ------------------=--------------------------------------------
http-apr-8080-exec-8           authType=null
http-apr-8080-exec-8        contentType=null
http-apr-8080-exec-8             header=Access-Control-Allow-Origin=http://localhost:9090
http-apr-8080-exec-8             header=Access-Control-Allow-Credentials=true
http-apr-8080-exec-8             header=Access-Control-Max-Age=10
http-apr-8080-exec-8             header=Access-Control-Allow-Methods=POST
http-apr-8080-exec-8             header=Access-Control-Allow-Headers=content-type,x-custom1,access-control-request-headers,accept,access-control-request-method,x-custom2,origin,x-custom3,x-requested-with
http-apr-8080-exec-8         remoteUser=null
http-apr-8080-exec-8             status=200
http-apr-8080-exec-8 END TIME          =26-Sep-2015 21:28:53
http-apr-8080-exec-8 ===============================================================

实际请求和响应 - 以 403 Forbidden 失败

http-apr-8080-exec-9 START TIME        =26-Sep-2015 21:28:53
http-apr-8080-exec-9         requestURI=/xxxx/zzzz
http-apr-8080-exec-9           authType=null
http-apr-8080-exec-9  characterEncoding=null
http-apr-8080-exec-9      contentLength=0
http-apr-8080-exec-9        contentType=null
http-apr-8080-exec-9        contextPath=/xxxx
http-apr-8080-exec-9             header=host=localhost:8080
http-apr-8080-exec-9             header=connection=keep-alive
http-apr-8080-exec-9             header=content-length=0
http-apr-8080-exec-9             header=pragma=no-cache
http-apr-8080-exec-9             header=cache-control=no-cache
http-apr-8080-exec-9             header=origin=http://localhost:9090
http-apr-8080-exec-9             header=x-custom1=aaaaa
http-apr-8080-exec-9             header=x-custom2=bbbbb
http-apr-8080-exec-9             header=user-agent=Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.42 Safari/537.36
http-apr-8080-exec-9             header=accept=*/*
http-apr-8080-exec-9             header=referer=http://localhost:9090/html/yyyy.html
http-apr-8080-exec-9             header=accept-encoding=gzip, deflate
http-apr-8080-exec-9             header=accept-language=en-US,en;q=0.8,ta;q=0.6
http-apr-8080-exec-9             locale=en_US
http-apr-8080-exec-9             method=POST
http-apr-8080-exec-9           pathInfo=null
http-apr-8080-exec-9           protocol=HTTP/1.1
http-apr-8080-exec-9        queryString=null
http-apr-8080-exec-9         remoteAddr=127.0.0.1
http-apr-8080-exec-9         remoteHost=127.0.0.1
http-apr-8080-exec-9         remoteUser=null
http-apr-8080-exec-9 requestedSessionId=null
http-apr-8080-exec-9             scheme=http
http-apr-8080-exec-9         serverName=localhost
http-apr-8080-exec-9         serverPort=8080
http-apr-8080-exec-9        servletPath=/zzzz
http-apr-8080-exec-9           isSecure=false
http-apr-8080-exec-9 ------------------=--------------------------------------------
http-apr-8080-exec-9 ------------------=--------------------------------------------
http-apr-8080-exec-9           authType=null
http-apr-8080-exec-9        contentType=text/plain
http-apr-8080-exec-9         remoteUser=null
http-apr-8080-exec-9             status=403
http-apr-8080-exec-9 END TIME          =26-Sep-2015 21:28:53
http-apr-8080-exec-9 =============================================================== 

我使用 Chrome 作为我的浏览器。

我想知道,当预检请求成功时,实际响应是否有可能得到 403 禁止?

另外请注意,我已经测试过从 Chrome 插件 Postman 和我可以得到预期的响应 成功没有 403 错误。

我完成了Tomcat CORSFilter flowchart 中给出的流程。我不清楚这里出了什么问题。感谢您在解决问题方面的帮助。谢谢。

【问题讨论】:

我尝试在 wso2 das 3.10 中使用 tomcat 进行日志记录,但失败了。 log4j.properties:org.apache.catalina.filters=DEBUG 你的日志设置是什么? 【参考方案1】:

要添加到 this answer,最可能的原因是 Postman 可能会自动将 Content-Type 添加到请求中,而不是浏览器本身。

【讨论】:

【参考方案2】:

我遇到了完全相同的问题。解决方案其实很简单。

“我注意到 HTTP POST 请求以某种方式需要填充 Content-Type HTTP 标头。”

尝试将 Content-Type 添加到您的 POST 请求中。

【讨论】:

以上是关于Tomcat CORS:预检成功,但实际请求失败,403 被禁止的主要内容,如果未能解决你的问题,请参考以下文章

CORS:预检通过,主请求完成 w/200,但浏览器仍然有 Origin 错误

CORS 问题:预检响应具有无效的 HTTP 状态代码 403

在启动中启用 CORS 失败并出现预检错误

IE 11 上 CORS 预检请求的奇怪问题失败

CORS 预检响应未成功

获取 api 预检请求失败