来自 Angular 的 HTTP 请求作为 OPTIONS 而不是 POST 发送 [英] HTTP request from Angular sent as OPTIONS instead of POST
问题描述
我正在尝试从我的 angular.js 应用程序向我的服务器发送一些 HTTP 请求,但我需要解决一些 CORS 错误.
使用以下代码发出 HTTP 请求:
functions.test = function(foo, bar) {返回 $http({方法:'POST',url: api_endpoint + 'test',标题:{'foo': '值',内容类型":应用程序/json"},数据: {酒吧:'价值'}});};
第一次尝试以一些 CORS 错误告终.所以我在我的 PHP 脚本中添加了以下几行:
header('Access-Control-Allow-Origin: *');header('访问控制允许方法:POST、GET、OPTIONS、DELETE、PUT');header('Access-Control-Allow-Headers: X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding, X-Auth-Token, content-type');
现在消除了第一个错误.
现在 Chrome 的开发者控制台显示了以下错误:
<块引用>angular.js:12011 选项
我无法想象如何解决这个问题(以及如何理解)为什么请求会在本地主机上作为 OPTIONS
发送,并作为 POST
发送到远程服务器.有没有办法解决这个奇怪的问题?
TL;DR answer
说明
OPTIONS
请求被称为 飞行前请求,它是 跨源资源共享 (CORS).浏览器使用它来检查是否允许来自特定域的请求,如下所示:
- 浏览器想要向特定 URL 发送请求,假设是一个
POST
请求,内容类型为application/json
- 首先,它将pre-flight
OPTIONS
请求发送到相同的 URL - 接下来的内容取决于飞行前请求的响应 HTTP 状态代码:
- 如果服务器回复一个非
2XX
状态响应,浏览器将不会发送实际请求(因为他现在知道无论如何都会被拒绝) - 如果服务器以
HTTP 200 OK
(或任何其他2XX
)响应回复,浏览器将发送实际请求,POST
在你的情况下
- 如果服务器回复一个非
解决方案
因此,在您的情况下,存在正确的标头,您只需确保飞行前请求的响应 HTTP 状态代码为 200 OK
或其他一些成功的 (2XX
).
详细说明
简单请求
在某些情况下,浏览器不会发送飞行前请求,这些请求是所谓的简单请求,用于以下情况条件:
<块引用>- 允许的方法之一:-
GET
-头部
-POST
- 除了由用户代理自动设置的标头(例如,Connection、User-Agent 等)外,唯一允许手动设置的标头如下:
接受
接受语言
内容语言
Content-Type
(但请注意以下附加要求)DPR
下行链接
保存数据
视口宽度
宽度
- Content-Type 标头的唯一允许值是:
application/x-www-form-urlencoded
multipart/form-data
text/plain
- 没有在请求中使用的任何
XMLHttpRequestUpload
对象上注册事件侦听器;这些是使用XMLHttpRequest.upload
属性访问的. - 请求中没有使用
ReadableStream
对象.
此类请求是直接发送的,如果请求与 CORS 规则不匹配,服务器会简单地成功处理请求或回复错误.在任何情况下,响应都将包含 CORS 标头 Access-Control-Allow-*
.
预检请求
如果实际请求不满足简单请求条件,浏览器会发送飞行前请求,最常见的情况是:
- 使用
application/xml
或application/json
等自定义内容类型 - 请求方法不是
GET
、HEAD
或POST
POST
方法是一种不同于application/x-www-form-urlencoded
、multipart/form-data
或text/plain
您需要确保对飞行前请求的响应具有以下属性:
- 成功的HTTP状态码,即
200 OK
- header
Access-Control-Allow-Origin: *
(通配符*
允许来自任何域的请求,您可以使用任何特定域来限制此处的访问当然)
从另一方面来说,服务器可以拒绝 CORS 请求,只需向飞行前请求发送具有以下属性的响应:
- 非成功的 HTTP 代码(即除了
2XX
) - 成功的 HTTP 代码(例如
200 OK
),但没有任何 CORS 标头(即Access-Control-Allow-*
)
请参阅 Mozilla Developer Network 上的文档 或例如HTML5Rocks 的 CORS 教程了解详情.
I'm trying to send some HTTP requests from my angular.js application to my server, but I need to solve some CORS errors.
The HTTP request is made using the following code:
functions.test = function(foo, bar) {
return $http({
method: 'POST',
url: api_endpoint + 'test',
headers: {
'foo': 'value',
'content-type': 'application/json'
},
data: {
bar:'value'
}
});
};
The first try ended up with some CORS errors. So I've added the following lines to my PHP script:
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT');
header('Access-Control-Allow-Headers: X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding, X-Auth-Token, content-type');
The first error is now eliminated.
Now the Chrome's developer console shows me the following errors:
angular.js:12011 OPTIONS http://localhost:8000/test (anonymous function)
423ef03a:1 XMLHttpRequest cannot load http://localhost:8000/test. Response for preflight has invalid HTTP status code 400
and the network request looks like I expected (HTTP status 400
is also expected):
I can't imagine how to solve the thing (and how to understand) why the request will send on localhost as OPTIONS
and to remote servers as POST
. Is there a solution how to fix this strange issue?
TL;DR answer
Explanation
The OPTIONS
request is so called pre-flight request, which is part of Cross-origin resource sharing (CORS). Browsers use it to check if a request is allowed from a particular domain as follows:
- The browser wants to send a request to a particular URL, let's say a
POST
request with theapplication/json
content type - First, it sends the pre-flight
OPTIONS
request to the same URL - What follows depends on the pre-flight request's response HTTP status code:
- If the server replies with a non-
2XX
status response, the browser won't send the actual request (because he knows now that it would be refused anyway) - If the server replies with a
HTTP 200 OK
(or any other2XX
) response, the browser will send the actual request,POST
in your case
- If the server replies with a non-
Solution
So, in your case, the proper header is present, you just have to make sure the pre-flight request's response HTTP status code is 200 OK
or some other successful one (2XX
).
Detailed Explanation
Simple requests
Browsers are not sending the pre-flight requests in some cases, those are so-called simple requests and are used in the following conditions:
- One of the allowed methods: -
GET
-HEAD
-POST
- Apart from the headers automatically set by the user agent (for example, Connection, User-Agent, etc.), the only headers which are allowed to be manually set are the following:
Accept
Accept-Language
Content-Language
Content-Type
(but note the additional requirements below)DPR
Downlink
Save-Data
Viewport-Width
Width
- The only allowed values for the Content-Type header are:
application/x-www-form-urlencoded
multipart/form-data
text/plain
- No event listeners are registered on any
XMLHttpRequestUpload
object used in the request; these are accessed using theXMLHttpRequest.upload
property. - No
ReadableStream
object is used in the request.
Such requests are sent directly and the server simply successfully processes the request or replies with an error in case it didn't match the CORS rules. In any case, the response will contain the CORS headers Access-Control-Allow-*
.
Pre-flighted requests
Browsers are sending the pre-flight requests if the actual request doesn't meet the simple request conditions, the most usually:
- custom content types like
application/xml
orapplication/json
, etc., are used - the request method is other than
GET
,HEAD
orPOST
- the
POST
method is of an another content type thanapplication/x-www-form-urlencoded
,multipart/form-data
ortext/plain
You need to make sure that the response to the pre-flight request has the following attributes:
- successful HTTP status code, i.e.
200 OK
- header
Access-Control-Allow-Origin: *
(a wildcard*
allows a request from any domain, you can use any specific domain to restrict the access here of course)
From the other side, the server may refuse the CORS request simply by sending a response to the pre-flight request with the following attributes:
- non-success HTTP code (i.e. other than
2XX
) - success HTTP code (e.g.
200 OK
), but without any CORS header (i.e.Access-Control-Allow-*
)
See the documentation on Mozilla Developer Network or for example HTML5Rocks' CORS tutorial for details.
这篇关于来自 Angular 的 HTTP 请求作为 OPTIONS 而不是 POST 发送的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!