如何将 CORS 标头设置为内部服务器错误响应?
Posted
技术标签:
【中文标题】如何将 CORS 标头设置为内部服务器错误响应?【英文标题】:How to set CORS headers into internal server error responses? 【发布时间】:2015-03-14 03:02:57 【问题描述】:我有一个带有 resteasy 提供的 REST 接口的 java 应用程序服务器,并且我有下面的 CORS 过滤器
@Provider
public class CORSFilter implements ContainerResponseFilter
public void filter(ContainerRequestContext cReq, ContainerResponseContext cResp)
cResp.getHeaders().add("Access-Control-Allow-Origin", "*");
cResp.getHeaders().add("Access-Control-Allow-Headers", "origin, content-type, accept, authorization, auth-token");
cResp.getHeaders().add("Access-Control-Allow-Credentials", "true");
cResp.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
cResp.getHeaders().add("Access-Control-Max-Age", "1209600");
所有请求都返回 CORS 标头:
OPTIONS 200 OK
Access-Control-Allow-Credentials:"true"
Access-Control-Allow-Headers:"origin, content-type, accept, authorization, auth-token"
Access-Control-Allow-Methods:"GET, POST, PUT, DELETE, OPTIONS, HEAD"
Access-Control-Allow-Origin:"*"
Access-Control-Max-Age:"1209600"
Allow:"HEAD, GET, OPTIONS"
Connection:"keep-alive"
Content-Length:"18"
Content-Type:"text/plain"
Date:"Thu, 15 Jan 2015 15:23:01 GMT"
Server:"WildFly/8"
除非我有一个返回错误代码 500 的内部异常:
GET 500 Internal Server Error
Connection:"keep-alive"
Content-Length:"8228"
Content-Type:"text/html; charset=UTF-8"
Date:"Thu, 15 Jan 2015 15:23:01 GMT"
如何让 500 个响应包含这些标头?
【问题讨论】:
请注意,浏览器通常不喜欢Access-Control-Allow-Origin: *
与 Access-Control-Allow-Credentials
结合使用 - 如果您想允许凭据,那么您应该允许特定来源而不是 *
。
【参考方案1】:
使用ExceptionMapper:
@Provider
public class CorsExceptionMapper implements ExceptionMapper<Exception>
@Override
public Response toResponse(Exception ex)
ResponseBuilder responseBuilder = Response.serverError();
responseBuilder.header("Access-Control-Allow-Origin", "*");
responseBuilder.header("Access-Control-Allow-Headers", "origin, content-type, accept, authorization, auth-token");
responseBuilder.header("Access-Control-Allow-Credentials", "true");
responseBuilder.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
responseBuilder.header("Access-Control-Max-Age", "1209600");
return responseBuilder.build();
为避免标题重复,您应该使用:
cResp.getHeaders().putSingle()
在ContainerResponseFilter
。
【讨论】:
我本来打算这样建议的,但经过测试,我意识到如果在 JAX-RS 上下文中抛出异常,它仍然会通过响应过滤器。所以标题仍然存在。如果我们添加异常映射器,它实际上会将标头加倍。如果 OP 遇到标头未出现的问题,则异常可能发生在 JAX-RS 范围之外,可能需要在其他地方处理。 谢谢!这很烦人。也许最简单的解决方案是在ContainerResponseFilter
中使用cResp.getHeaders().putSingle()
?
那应该覆盖它吧?没有检查,但似乎是正确的。
是的:Set the key's value to be a one item list consisting of the supplied value. Any existing values will be replaced.
我使用了你提供的代码,但所有参数都在标头中复制,所以我只是省略了 header() 调用,它起作用了【参考方案2】:
ExceptionMapper 无法在我发现的所有场景中工作。似乎还有其他一些容器响应,我们需要另一种过滤器类型。特别是对j_security_check
(FORM登录)don't get CORS headers added的请求的响应。因此,我没有同时使用 ContainerResponseFilter
和 ExceptionMapper
并且仍然有一些没有 CORS 标头的响应,而是选择了 Undertow 过滤器。缺点是它仅适用于基于 Undertow 的服务器(Jboss EAP、Wildfly、Wildfly Swarm),但优点是它适用于所有响应。
我编写了一个特定的过滤器来添加作为 JBoss 模块安装的 CORS 标头,并且可以从 standalone.xml
进行配置。在这里找到它:
undertow-cors-filter
下载 .zip 文件并将其解压缩到 Wildfly 根文件夹中。然后给standalone.xml
添加一个filter
配置:
<filters>
<filter name="undertow-cors-filter" class-name="com.stijndewitt.undertow.cors.Filter" module="com.stijndewitt.undertow.cors">
<param name="urlPattern" value="^http(s)?://([^/]+)(:([^/]+))?(/([^/])+)?/api(/.*)?$" />
<param name="policyClass" value="com.stijndewitt.undertow.cors.AllowMatching" />
<param name="policyParam" value="^http(s)?://(www\.)?example\.(com|org)$" />
</filter>
</filters>
将filter-ref
添加到host
元素(仍在standalone.xml
):
<host name="default-host" alias="localhost">
<filter-ref name="undertow-cors-filter" />
</host>
这将添加 CORS 标头,允许来源 http(s)://(www.)example.(com|org) 访问对路径段 "/api"
下 URL 的请求的所有响应。
更改filter
定义中的param
s 以配置行为。有 3 个策略类可用,AllowAll
、AllowMatching
和 Whitelist
,如果需要,您可以编写自己的自定义策略。
【讨论】:
以上是关于如何将 CORS 标头设置为内部服务器错误响应?的主要内容,如果未能解决你的问题,请参考以下文章
NestJs Socket io 适配器:如果使用 false 调用 allowFunction,服务器不会将 CORS 标头添加到握手的响应中。错误或配置错误?
如何将 CORS 标头添加到 Jersey 2 中灰熊服务器的 StaticHttpHandler 提供的响应?