POST 的跨域

Posted

技术标签:

【中文标题】POST 的跨域【英文标题】:Cross origin for POST 【发布时间】:2019-03-29 02:10:07 【问题描述】:

我有一个带有一些 Jersey 休息服务的 Jetty http 服务器。这些服务是从运行在 Node 服务器上的 React 网站调用的。

由于此设置的跨源性质,我不得不添加一些 HTTP 标头。基本上,我所有的网络服务都会返回一个createOkResult(),它的创建方式如下。

@POST
@Path("orders/quickfilter")
@Consumes(MediaType.APPLICATION_JSON)
public Response getQuickFilterProductionOrders(String data) 

  ...
  return createOkResult(json.toString());


protected Response createOkResult(Object result)

  return buildCrossOrigin(Response.ok().entity(result));


protected static Response buildCrossOrigin(Response.ResponseBuilder responseBuilder)

  return responseBuilder.header("Access-Control-Allow-Origin", "*")
          .header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT")
          .allow("OPTIONS")
          .build();

对于运行良好的 @GET 网络服务。但是当我创建一个@POST 服务时,我就是无法让它工作。

网络浏览器(chrome 和 firefox)返回这些类型的错误:

从源“http://localhost:3000”访问“http://localhost:59187/rs/production/orders/quickfilter”处的 XMLHttpRequest 已被 CORS 策略阻止:请求的资源上不存在“Access-Control-Allow-Origin”标头。

所以,乍一看,我会认为标题仍然丢失。问题是,当我使用 Postman 之类的工具测试此服务时,所有标头都已到位,服务甚至返回请求的数据。

这是 POST 请求的屏幕截图。

从我的前端(在节点服务器上运行),我使用 axios API,它使用 Promise,我的请求如下所示:

const url = "http://localhost:59187/rs/production/orders/quickfilter";
const data = JSON.stringify(request);
const headers =  headers:  "Content-Type": "application/json"  ;
const promise = axios.post(url, data, headers);

现在我有一个 HTTP 错误 500,如果我删除内容类型标头,我会得到一个不受支持的媒体异常。所以,我有理由相信内容类型没问题。

【问题讨论】:

Postman 并不局限于浏览器的跨源策略。您需要使用过滤器来添加 CORS 标头。资源方法不适用于预检请求,因为预检是 OPTIONS 请求。请参阅this post 了解更多信息。 感谢您的链接,我会在早上第一件事尝试一下。 :) 阅读全文,尤其是“更新”,了解它是如何工作的。 Why does my javascript get a "No 'Access-Control-Allow-Origin' header is present on the requested resource" error when Postman does not?的可能重复 @sideshowbarker 是和否。现有的问题更多是关于“为什么邮递员不同”(即前端),而我的问题显然是后端缺少配置。但我可以想象,第一眼看上去很相似。因为巧合,我最初也试图通过使用邮递员来排除一些事情。 - 但实际上,这个问题与邮递员本身无关。 【参考方案1】:

Paul Samsotha 为我指明了正确的方向。 我最终为ServletContextHandler 添加了一个过滤器。与链接的文章不同,我真的不必从头开始创建该过滤器。我可以使用一个现有的过滤器类:即org.eclipse.jetty.servlets.CrossOriginFilter

FilterHolder filterHolder = context.addFilter(CrossOriginFilter.class, "/*", EnumSet.allOf(DispatcherType.class));
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "GET,PUT,POST,DELETE,OPTIONS");
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, "*");
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "Content-Type,Authorization,X-Requested-With,Content-Length,Accept,Origin");
filterHolder.setInitParameter(CrossOriginFilter.ALLOW_CREDENTIALS_PARAM, "true");
filterHolder.setInitParameter(CrossOriginFilter.CHAIN_PREFLIGHT_PARAM, "false");

上面的一些参数可能会被忽略,因为它们是默认值。但对我来说似乎至关重要的是,将CHAIN_PREFLIGHT_PARAM 设置为false

一个很好的副作用是我可以简化实际服务的代码。他们不再需要添加特殊的标头,相比之下,他们现在只需返回 Response.ok().entity(result).build();

【讨论】:

以上是关于POST 的跨域的主要内容,如果未能解决你的问题,请参考以下文章

html5 postMessage解决跨域跨窗口消息传递

html5 postMessage解决跨域跨窗口消息传递

Ajax解决跨域--设置CORS响应头实现跨域

跨域分析以及通解

前端常见跨域解决方案

前端常见跨域解决方案