I'm trying to setup AngularJS to communicate with a cross-origin resource where the asset host which delivers my template files is on a different domain and therefore the XHR request that angular performs must be cross-domain. I've added the appropriate CORS header to my server for the HTTP request to make this work, but it doesn't seem to work. The problem is that when I inspect the HTTP requests in my browser (chrome) the request sent to the asset file is an OPTIONS request (it should be a GET request).

我不确定这是AngularJS中的一个bug,还是我需要配置一些东西。根据我的理解,XHR包装器不能做出一个OPTIONS HTTP请求,所以看起来就像浏览器在执行GET请求之前试图弄清楚是否“允许”首先下载资产。如果是这种情况,那么我是否需要与资产主机一起设置CORS头(Access-Control-Allow-Origin: http://asset.host…)?


当前回答

如果你正在使用Jersey的REST API,你可以这样做

你不需要改变你的webservices实现。

我会解释Jersey 2.x

1)首先添加一个ResponseFilter,如下所示

import java.io.IOException;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;

public class CorsResponseFilter implements ContainerResponseFilter {

@Override
public void filter(ContainerRequestContext requestContext,   ContainerResponseContext responseContext)
    throws IOException {
        responseContext.getHeaders().add("Access-Control-Allow-Origin","*");
        responseContext.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");

  }
}

2)然后在web.xml中,在jersey servlet声明中添加如下内容

    <init-param>
        <param-name>jersey.config.server.provider.classnames</param-name>
        <param-value>YOUR PACKAGE.CorsResponseFilter</param-value>
    </init-param>

其他回答

在pkozlowski的评论中有完美的描述。 我有工作解决方案与AngularJS 1.2.6和ASP。NET Web Api,但当我将AngularJS升级到1.3.3时,请求失败。

Solution for Web Api server was to add handling of the OPTIONS requests at the beginning of configuration method (more info in this blog post): app.Use(async (context, next) => { IOwinRequest req = context.Request; IOwinResponse res = context.Response; if (req.Path.StartsWithSegments(new PathString("/Token"))) { var origin = req.Headers.Get("Origin"); if (!string.IsNullOrEmpty(origin)) { res.Headers.Set("Access-Control-Allow-Origin", origin); } if (req.Method == "OPTIONS") { res.StatusCode = 200; res.Headers.AppendCommaSeparatedValues("Access-Control-Allow-Methods", "GET", "POST"); res.Headers.AppendCommaSeparatedValues("Access-Control-Allow-Headers", "authorization", "content-type"); return; } } await next(); });

对于一个带有API的IIS MVC 5 / Angular CLI(是的,我很清楚你的问题是Angular JS)项目,我做了以下工作:

网络。在<system. Config。网络服务器>节点

    <staticContent>
      <remove fileExtension=".woff2" />
      <mimeMap fileExtension=".woff2" mimeType="font/woff2" />
    </staticContent>
    <httpProtocol>
      <customHeaders>
        <clear />
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Headers" value="Content-Type, atv2" />
        <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS"/>
      </customHeaders>
    </httpProtocol>

global.asax.cs

protected void Application_BeginRequest() {
  if (Request.Headers.AllKeys.Contains("Origin", StringComparer.OrdinalIgnoreCase) && Request.HttpMethod == "OPTIONS") {
    Response.Flush();
    Response.End();
  }
}

这应该可以解决MVC和WebAPI的问题,而不需要做所有其他的事情。然后我在Angular CLI项目中创建了一个HttpInterceptor,它会自动添加相关的头信息。希望这能帮助有类似情况的人。

OPTIONS请求绝不是AngularJS的错误,这是跨源资源共享标准要求浏览器的行为。请参考此文件:https://developer.mozilla.org/en-US/docs/HTTP_access_control,其中“概述”部分说:

The Cross-Origin Resource Sharing standard works by adding new HTTP headers that allow servers to describe the set of origins that are permitted to read that information using a web browser. Additionally, for HTTP request methods that can cause side-effects on user data (in particular; for HTTP methods other than GET, or for POST usage with certain MIME types). The specification mandates that browsers "preflight" the request, soliciting supported methods from the server with an HTTP OPTIONS request header, and then, upon "approval" from the server, sending the actual request with the actual HTTP request method. Servers can also notify clients whether "credentials" (including Cookies and HTTP Authentication data) should be sent with requests.

提供一个适用于所有WWW服务器的通用解决方案是非常困难的,因为设置取决于服务器本身和你打算支持的HTTP动词。我鼓励您阅读这篇优秀的文章(http://www.html5rocks.com/en/tutorials/cors/),其中有更多关于服务器需要发送的确切头部的详细信息。

这解决了我的问题:

$http.defaults.headers.post["Content-Type"] = "text/plain";

来的有点晚了

如果你正在使用Angular 7(或5/6/7)和PHP作为API,并且仍然得到这个错误,尝试在端点(PHP API)中添加以下头选项。

 header("Access-Control-Allow-Origin: *");
 header("Access-Control-Allow-Methods: PUT, GET, POST, PUT, OPTIONS, DELETE, PATCH");
 header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization");

注意:只需要Access-Control-Allow-Methods。但是,我在这里粘贴了另外两个Access-Control-Allow-Origin和Access-Control-Allow-Headers,只是因为你需要正确地设置所有这些,以便Angular应用能够正确地与你的API对话。

希望这能帮助到一些人。

欢呼。