如何将 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的请求的响应。因此,我没有同时使用 ContainerResponseFilterExceptionMapper 并且仍然有一些没有 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 定义中的params 以​​配置行为。有 3 个策略类可用,AllowAllAllowMatchingWhitelist,如果需要,您可以编写自己的自定义策略。

【讨论】:

以上是关于如何将 CORS 标头设置为内部服务器错误响应?的主要内容,如果未能解决你的问题,请参考以下文章

添加授权标头时出现CORS错误

NestJs Socket io 适配器:如果使用 false 调用 allowFunction,服务器不会将 CORS 标头添加到握手的响应中。错误或配置错误?

如何将 CORS 标头添加到 Jersey 2 中灰熊服务器的 StaticHttpHandler 提供的响应?

即使在设置 CORS 标头和服务器响应之后,Angular 和 laravel 的 CORS 问题[重复]

没有将 Cors 标头添加到响应中

尽管端点在 apicontroller 内部的行为中使用了 cors 类,但 CORS 标头未添加到响应中