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…)?
来的有点晚了
如果你正在使用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对话。
希望这能帮助到一些人。
欢呼。
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/),其中有更多关于服务器需要发送的确切头部的详细信息。
我放弃了解决这个问题。
我的IIS网络。config中有相关的“Access-Control-Allow-Methods”,我尝试在我的Angular代码中添加配置设置,但在花了几个小时试图让Chrome调用一个跨域JSON web服务后,我悲惨地放弃了。
最后,我添加了一个愚蠢的ASP。Net handler网页,让它调用JSON web服务,并返回结果。它在两分钟内就运行起来了。
下面是我使用的代码:
public class LoadJSONData : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
string URL = "......";
using (var client = new HttpClient())
{
// New code:
client.BaseAddress = new Uri(URL);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("Authorization", "Basic AUTHORIZATION_STRING");
HttpResponseMessage response = client.GetAsync(URL).Result;
if (response.IsSuccessStatusCode)
{
var content = response.Content.ReadAsStringAsync().Result;
context.Response.Write("Success: " + content);
}
else
{
context.Response.Write(response.StatusCode + " : Message - " + response.ReasonPhrase);
}
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
在我的Angular控制器中…
$http.get("/Handlers/LoadJSONData.ashx")
.success(function (data) {
....
});
我相信有一种更简单/更通用的方式来做这件事,但生命太短暂了…
这对我很有效,现在我可以继续做正常的工作了!!
在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();
});