来自Angular的HTTP请求以OPTIONS而非POST的形式发送

Dav*_*vid 11 javascript php http cors angularjs

我试图将一些HTTP请求从我的angular.js应用程序发送到服务器,但是我需要解决一些CORS错误。

使用以下代码发出HTTP请求:

functions.test = function(foo, bar) {
    return $http({
        method: 'POST',
        url: api_endpoint + 'test',
        headers: {
            'foo': 'value',
            'content-type': 'application/json'
        },
        data: {
            bar:'value'
        }
    });
};
Run Code Online (Sandbox Code Playgroud)

第一次尝试以一些CORS错误结束。因此,我在PHP脚本中添加了以下几行:

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');
Run Code Online (Sandbox Code Playgroud)

现在消除了第一个错误。

现在,Chrome的开发者控制台向我显示以下错误:

angular.js:12011选项http:// localhost:8000 / test(匿名函数)

423ef03a:1 XMLHttpRequest无法加载 http:// localhost:8000 / test。飞行前的响应具有无效的HTTP状态代码400

并且网络请求看起来像我预期的那样(HTTP状态400也是预期的):

网络请求

我无法想象如何解决问题(以及如何理解),为什么请求将在localhost OPTIONS和上发送到远程服务器POST。有解决方案如何解决这个奇怪的问题?

Daw*_*žan 23

OPTIONS请求被称为飞行前请求,它是跨域资源共享(CORS)的一部分。浏览器使用它来检查是否允许来自特定域的请求,如下所示:

  1. 浏览器要发送请求,比方说内容类型的POST请求application/json
  2. 所以首先,它发送飞行前 OPTIONS请求
  3. 如果服务器回复非2XX状态响应,则浏览器将不会发送实际请求(因为他现在知道无论如何都会被拒绝)
  4. 如果浏览器收到HTTP 200 OK对飞行前请求的响应,则发送实际请求(POST在您的情况下)

理论

简单的要求

在某些情况下,浏览器不会发送飞行前请求,这些请求即所谓的简单请求,它们在以下情况下使用:

  • 允许的方法之一:
    • GET
    • HEAD
    • POST
  • 除了由用户代理自动设置的标头(例如,Connection,User-Agent等)之外,允许手动设置的标头只有以下几种:
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type (但请注意下面的其他要求)
    • DPR
    • Downlink
    • Save-Data
    • Viewport-Width
    • Width
  • Content-Type标头的唯一允许值为:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain
  • 没有在事件中使用的任何XMLHttpRequestUpload对象上注册事件侦听器;使用XMLHttpRequest.upload属性访问这些。
  • ReadableStream请求中未使用任何对象。

此类请求将直接发送,如果服务器不符合CORS规则,则服务器会简单地成功处理请求或回复错误。无论如何,响应都将包含CORS标头Access-Control-Allow-*

预先提出的要求

如果实际请求不满足简单的请求条件,则浏览器发送飞行前请求,通常是:

  • 使用自定义内容类型,例如application/xmlapplication/json,等等。
  • 请求的方法比其它GETHEADPOST
  • POST方法是一个另一种内容类型比application/x-www-form-urlencodedmultipart/form-datatext/plain

您需要确保对飞行前请求的响应具有以下属性

  • 成功的HTTP状态代码,即 200 OK
  • 标头Access-Control-Allow-Origin: *(通配符*允许来自任何域的请求,您当然可以在此处使用任何特定域来限制访问)

另一方面,服务器可以简单地通过发送对具有以下属性的飞行前请求的响应来拒绝CORS请求

  • 不成功的HTTP代码(例如2XX
  • 成功的HTTP代码(例如200 OK),但没有任何CORS标头(例如Access-Control-Allow-*

有关详细信息,请参见Mozilla开发人员网络上文档HTML5Rocks的CORS教程


TL; DR答案

因此,在您的情况下,存在正确的标头,您只需确保飞行前响应的HTTP状态代码为200 OK或其他成功的HTTP状态码(2XX