AngularJS为跨源资源执行OPTIONS HTTP请求

mat*_*sko 262 cross-domain cors angularjs preflight

我正在尝试设置AngularJS与跨源资源进行通信,其中传递我的模板文件的资产主机位于不同的域上,因此角度执行的XHR请求必须是跨域的.我已经为我的服务器添加了适当的CORS标头,以便使其工作,但它似乎不起作用.问题是,当我在浏览器(chrome)中检查HTTP请求时,发送到资产文件的请求是OPTIONS请求(它应该是GET请求).

我不确定这是AngularJS中的错误还是我需要配置一些东西.根据我的理解,XHR包装器无法发出OPTIONS HTTP请求,因此看起来浏览器正在试图确定在执行GET请求之前是否"允许"首先下载资产.如果是这种情况,那么我是否还需要使用资产主机设置CORS标头(Access-Control-Allow-Origin:http://asset.host ..)?

pko*_*rce 224

OPTIONS请求绝不是AngularJS错误,这就是跨源资源共享标准要求浏览器行为的方式.请参阅此文档:https://developer.mozilla.org/en-US/docs/HTTP_access_control,其中"概述"部分中的内容如下:

跨源资源共享标准的工作原理是添加新的HTTP标头,允许服务器描述允许使用Web浏览器读取该信息的起源集.此外,对于可能对用户数据造成副作用的HTTP请求方法(特别是;对于GET以外的HTTP方法,或对某些MIME类型的POST使用).规范要求浏览器"预检"请求,使用HTTP OPTIONS请求标头从服务器请求支持的方法,然后在服务器"批准"时,使用实际的HTTP请求方法发送实际请求.服务器还可以通知客户端是否应随请求一起发送"凭据"(包括Cookie和HTTP身份验证数据).

很难提供适用于所有WWW服务器的通用解决方案,因为设置会因服务器本身和您打算支持的HTTP谓词而异.我建议您阅读这篇优秀文章(http://www.html5rocks.com/en/tutorials/cors/),其中详细介绍了服务器需要发送的确切标题.

  • @matsko你能详细说明你为解决这个问题所做的工作吗?我面临同样的问题,即AngularJS` $ resource` _POST_请求正在向我的后端ExpressJS服务器生成_OPTIONS_请求(在同一主机上;但是不同的端口). (23认同)
  • 对于所有下行选民 - 几乎不可能为所有网络服务器提供_exact_配置设置 - 在这种情况下答案将需要10页.相反,我链接到一篇提供更多细节的文章. (6认同)
  • 你是不对的,你不能指明一个答案 - 你需要在你的OPTIONS响应中添加标题,涵盖浏览器请求的所有标题,在我的例子中,使用chrome它是标题'accept'和'x -requested-与".在chrome中,我通过查看网络请求并查看chrome要求的内容来找出我需要添加的内容.我使用nodejs/expressjs作为支持,因此我创建了一个服务,该服务返回对OPTIONS请求的响应,该请求涵盖了所需的所有头文件.-1因为我无法使用这个答案来弄清楚要做什么,不得不自己搞清楚. (5认同)
  • @polettix甚至GET请求可以在浏览器中触发飞行前请求_如果使用自定义标头.在我链接的文章中检查"不那么简单的请求":http://www.html5rocks.com/en/tutorials/cors/#toc-making-a-cors-request.再一次,它是_browser的机制,而不是AngularJS. (4认同)
  • 我知道它已经过去了2年多,但是...... OP多次提到GET请求(强调我加入):«[...]发送到资产文件的请求是OPTIONS请求(**应该是一个GET请求**).»和«浏览器试图在执行GET请求之前确定是否"允许"首先下载资产**».那怎么可能不是AngularJS的错误呢?GET不应禁止预检请求吗? (2认同)
  • @pkozlowski.opensource我生活在(假)GET请求总是"简单"的假设下,绝对不是这样的:http://www.w3.org/TR/cors/ - 非常感谢让我仔细检查,学过的知识! (2认同)

JSt*_*ark 69

对于Angular 1.2.0rc1 +,您需要添加resourceUrlWhitelist.

1.2:发布版本他们添加了escapeForRegexp函数,因此您不再需要转义字符串.您可以直接添加网址

'http://sub*.assets.example.com/**' 
Run Code Online (Sandbox Code Playgroud)

确保为子文件夹添加**.这是一个适用于1.2的工作jsbin:http://jsbin.com/olavok/145/edit


1.2.0rc:如果你还在rc版本上,Angular 1.2.0rc1的解决方案如下:

.config(['$sceDelegateProvider', function($sceDelegateProvider) {
     $sceDelegateProvider.resourceUrlWhitelist(['self', /^https?:\/\/(cdn\.)?yourdomain.com/]);
 }])
Run Code Online (Sandbox Code Playgroud)

这是一个jsbin示例,它适用于1.2.0rc1:http://jsbin.com/olavok/144/edit


Pre 1.2:对于旧版本(参见http://better-inter.net/enabling-cors-in-angular-js/),您需要在配置中添加以下2行:

$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
Run Code Online (Sandbox Code Playgroud)

这是一个jsbin示例,适用于1.2版之前的版本:http://jsbin.com/olavok/11/edit

  • 这仅适用于GET请求,仍然无法在跨域上找到POST请求的解决方案. (14认同)
  • 将此答案与上面的user2304582答案结合起来应该适用于POST请求.您必须告诉您的服务器接受来自发送它的外部服务器的POST请求 (2认同)

use*_*845 61

注意:不确定它是否适用于最新版本的Angular.

原版的:

也可以覆盖OPTIONS请求(仅在Chrome中测试):

app.config(['$httpProvider', function ($httpProvider) {
  //Reset headers to avoid OPTIONS request (aka preflight)
  $httpProvider.defaults.headers.common = {};
  $httpProvider.defaults.headers.post = {};
  $httpProvider.defaults.headers.put = {};
  $httpProvider.defaults.headers.patch = {};
}]);
Run Code Online (Sandbox Code Playgroud)

  • 或者,可以单独在$ resource的方法上设置,而不是全局:`$ resource('http:// yourserver/yourentity /:id',{},{query:{method:'GET'}); (3认同)
  • 这有什么特别的吗?看起来很简单,但答案是如此深入到线程中?编辑:根本没用. (3认同)

小智 34

您的服务必须回复OPTIONS包含以下标题的请求:

Access-Control-Allow-Origin: [the same origin from the request]
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: [the same ACCESS-CONTROL-REQUEST-HEADERS from request]
Run Code Online (Sandbox Code Playgroud)

这是一个很好的文档:http://www.html5rocks.com/en/tutorials/cors/#toc-adding-cors-support-to-the-server


小智 20

同一份文件说

与简单请求(如上所述)不同,"预检"请求首先将HTTP OPTIONS请求头发送到另一域上的资源,以便确定实际请求是否可安全发送.跨站点请求是这样预检的,因为它们可能对用户数据有影响.特别是,如果出现以下情况,请求会被预检:

它使用GET或POST以外的方法.此外,如果POST用于发送具有除application/x-www-form-urlencoded,multipart/form-data或text/plain之外的Content-Type的请求数据,例如,如果POST请求将XML有效负载发送到服务器使用application/xml或text/xml,请求预检.

它在请求中设置自定义标头(例如,请求使用诸如X-PINGOTHER之类的标头)

当原始请求是Get而没有自定义标头时,浏览器不应该发出它现在所做的选项请求.问题是它生成一个标题X-Requested-With强制Options请求.有关如何删除此标头,请参阅https://github.com/angular/angular.js/pull/1454


Cem*_*nlı 10

这解决了我的问题:

$http.defaults.headers.post["Content-Type"] = "text/plain";
Run Code Online (Sandbox Code Playgroud)


Zak*_*dem 10

如果你使用的是nodeJS服务器,你可以使用这个库,它对我来说很好用https://github.com/expressjs/cors

var express = require('express')
  , cors = require('cors')
  , app = express();

app.use(cors());
Run Code Online (Sandbox Code Playgroud)

然后你可以做一个npm update.


小智 5

这是我在 ASP.NET 上解决此问题的方法

  • 首先,您应该添加 nuget 包Microsoft.AspNet.WebApi.Cors

  • 然后修改文件App_Start\WebApiConfig.cs

    public static class WebApiConfig    
    {
       public static void Register(HttpConfiguration config)
       {
          config.EnableCors();
    
          ...
       }    
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 在您的控制器类上添加此属性

    [EnableCors(origins: "*", headers: "*", methods: "*")]
    public class MyController : ApiController
    {  
        [AcceptVerbs("POST")]
        public IHttpActionResult Post([FromBody]YourDataType data)
        {
             ...
             return Ok(result);
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 我能够通过这种方式将 json 发送到操作

    $http({
            method: 'POST',
            data: JSON.stringify(data),
            url: 'actionurl',
            headers: {
                'Content-Type': 'application/json; charset=UTF-8'
            }
        }).then(...)
    
    Run Code Online (Sandbox Code Playgroud)

参考: 在 ASP.NET Web API 2 中启用跨源请求