Angular资源如何保留ajax标头并同时启用cors

Posted

技术标签:

【中文标题】Angular资源如何保留ajax标头并同时启用cors【英文标题】:Angular resource how to keep ajax header and enable cors at the same time 【发布时间】:2015-09-24 15:49:22 【问题描述】:

在我的 ng-resource 文件中,我启用了 ajax 标头:

var app = angular.module('custom_resource', ['ngResource'])

app.config(['$httpProvider', function($httpProvider) 
    //enable XMLHttpRequest, to indicate it's ajax request
    //Note: this disables CORS
    $httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';
])

app.factory('Article', ['$resource', function($resource) 
    return $resource('/article/api/:articleId', articleId: '@_id', 
        update: method: 'PUT',
        query: method: 'GET', isArray: true
    )
])

这样我就可以相应地分离 ajax 和非 ajax 请求和响应(发送 json 数据,如 res.json(data),或发送整个 html 页面,如 res.render('a.html')

例如,在我的错误处理程序中,我需要决定呈现 error.html 页面还是只发送错误消息:

exports.finalHandler = function(err, req, res, next) 
    res.status(err.status || 500)
    var errorMessage = helper.isProduction() ? '' : (err.message || 'unknown error')

    if (req.xhr) 
        res.json(message: errorMessage)
    
    else 
        res.render(dir.error + '/error_page.ejs')
    

但现在我需要向其他站点发出 CORS 请求。是否可以在保留 ajax 标头的同时进行 CORS 请求?或其他方式我可以识别来自服务器的 ajax 和非 ajax 请求?

如果我的问题不清楚,这里有一篇关于 Angular 和 CORS 的相关文章 http://better-inter.net/enabling-cors-in-angular-js/

基本上,我们需要删除 xhr 标头以启用其他服务器的 cors,但我需要自己的服务器的标头

编辑2:

今天我尝试集成谷歌地图,我得到了这个错误:

XMLHttpRequest cannot load http://maps.googleapis.com/maps/api/geocode/json?address=Singapore&sensor=false. Request header field X-Requested-With is not allowed by Access-Control-Allow-Headers.

【问题讨论】:

【参考方案1】:

如果你使用的是最新版本的 angular.js,你可以这样做

首先,添加 xhr 标头(您所做的是正确的)

    $httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

然后在你的谷歌地图搜索功能中

var searchAddress = function(address) 
    var params = address: address, sensor: false;
    //Note: google map rejects XHR header
    $http.get(google_map_web_api_url, params: params, headers: 'X-Requested-With': undefined)
        .success(function(data, status, headers, config) 
        )
        .error(function(data, status, headers, config) 
        )

传入的headers config 参数将删除每个请求基数的xhr,这意味着您的ng-resource 请求不会受到影响

【讨论】:

【参考方案2】:

在 XHR 请求上设置自定义标头会触发预检请求。

因此,它不会禁用 CORS,但您的服务器很可能没有处理预检请求。

灵感来自这篇文章:https://remysharp.com/2011/04/21/getting-cors-working

解决方案应该是使用cors 模块并将以下内容添加到您的路由之前的node.js 代码中:

var corsOptions = 
    origin: true,
    methods: ['GET', 'PUT', 'POST'],
    allowedHeaders: ['X-Requested-With','Content-Type', 'Authorization']
;

app.options('*', cors(corsOptions)); //You may also be just fine with the default options

您可以阅读更多内容:https://github.com/expressjs/cors

【讨论】:

该代码是在服务器还是客户端?我想连接其他不属于我的服务器 该代码在服务器上。如果您正在使用另一台服务器,这意味着他们没有正确处理选项/预检请求。类似/更多信息:***.com/questions/20786405/… 这个问题也是 AngularJS 默认删除“X-Requested-With”的原因。 goo.gl/Uxyjlh 第二个解决方案:***.com/questions/15945118/… 可能是一种方法。如果这不起作用,一种糟糕但有效的方法是向正文添加一个变量以指示 ajax 请求。但最好的选择是联系其他网站并要求他们修复它。 其他选项是你无法使用 CORS 是使用 JSONP。 使用 jsonp 还是 cors 不是由我决定的。它是需要 CORS 的远程服务器。但我的 nodejs 服务器需要 xhr 标头来区分 ajax/非 ajax 请求【参考方案3】:

您可以尝试使用cors package

【讨论】:

这不是我想要的。我不需要在我的服务器上启用 cors。其他网站已经支持 CORS。【参考方案4】:

首先,解决您最关心的问题是否可以在保留 ajax 标头的同时进行 CORS 请求?:答案是可以,前提是您访问的网站允许来自您或任何其他外部客户的请求。

你写道:

//Note: this disables CORS
$httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';

但我不明白你的意思,它“禁用 CORS”。 X-Requested-With 标头不是标准标头,将非标准标头添加到请求(由浏览器发出)的已知效果是触发飞行前请求 [3]。

如果您感兴趣的其他站点将其服务器设置为拒绝处理并非来自其自己域的请求,那么无论您是否设置该标头,您的请求都会失败。

对于发送到您自己的服务器的请求,您似乎一切正常。否则,您可以通过在服务器响应中附加 Access-Control-Allow-Origin 标头来解决问题,如下所示:

    如果您需要允许来自特定域的请求

    response.set("Access-Control-Allow-Origin", "one-host-domain, your-host-domain, some-other-host-domain"); // second argument is a comma-delimited list of allowed domains

    (对您来说,实际检查请求对象的来源可能会更好,如果基于预先确定的列表中的存在允许,则发回完全相同的来源)。

    如果您需要允许所有请求,无论其来源如何

    response.set("Access-Control-Allow-Origin", "*");

应该可以,我希望它能为你消除疑虑。

有关在使用 AJAX 时处理 CORS 的更多信息:0、1 和 2。


编辑

在评论中的交流之后,我添加以下几点以进一步支持这个答案。

就像今天一样,唯一需要在客户端-服务器系统中禁用/启用 CORS 的是服务器。默认情况下,所有现代浏览器都允许跨源请求,您无需执行任何其他操作即可支持该功能。我知道您正在添加一个自定义标头来区分 AJAX 请求和其他请求?? AFAIK,该标头不会改变浏览器如何发出请求。

这是当今浏览器处理所有跨域请求的方式:对于所有请求方法(但通常除了 GET),浏览器会发送一个 pre- OPTION 方法的航班请求。如果目标服务器允许,则发送实际请求,否则请求失败。在服务器以拒绝响应的情况下,您或您使用的任何库都无能为力。这是我亲身经历的事实。

【讨论】:

请参考这篇文章,了解如何在 Angular 中启用 cors。 better-inter.net/enabling-cors-in-angular-js @OMGPOP,CORS 在所有现代浏览器上默认启用。您不需要 Angular 来利用该功能。 即使使用 xhr 标头?我最后更新了我的问题。 CORS 已启用,但如果您附加自定义标头,有时仍可能会阻止请求。 @Buyuk 这很奇怪。您能解释一下通过删除 xhr 标头来启用 cors 的解决方法吗?【参考方案5】:

我想到了 3 个解决方案: 1. 请求站点管理员在 CORS 中启用 x-requested-with 标头。 2.使用代理服务器。 3. 发送不带 x-requested-with 标头的请求。

This article 应该明确 CORS 的工作原理以及如何发出 CORS 请求。 特别是“简单请求”部分和“访问控制”部分,尤其是访问控制允许标头描述在这种情况下很重要。

正如它所说:对于简单的请求 access-control-allow-origin 就足够了。但是如果请求包含自定义头(默认不包含的头,例如x-requested-with头),则会触发预检请求,服务器对此请求的响应应该启用此自定义access-control-allow-headers 中的标头,通过将其值设置为“*”或自定义标头的名称 (x-requested-with)。 p>

希望它能让它更清楚一点。

【讨论】:

远程站点允许 CORS。但是,如果我在客户端上设置了 `$httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';`。然后它不工作 尽管远程服务器上启用了 CORS,但它需要设置在 CORS 请求中启用的自定义标头列表,或者指定它允许所有标头。如果您尝试设置的标头(在本例中为“X-Requested-With”),则请求将不起作用。正如我最近在我的项目中发现的那样,CORS 通常很难处理 :) 那有没有其他方法可以去掉 xhr 头,但在我的 node.js 服务器上仍然能够区分 ajax/non-ajax 请求? 您需要向远程服务器和您的服务器发送相同的请求吗?如果您可以将带有此标头的请求发送到您的服务器,并将没有此标头的请求发送到远程站点,那么它将起作用。如果不是这种情况,那么您可以尝试使用 User-Agent 标头区分 ajax 与非 ajax 请求。如果 User-Agent 将包含 Mozilla、Chrome 或其他浏览器名称,那么它很可能是一个 ajax 调用,如果不是它的正常请求。 你能提供更多细节(最好有一些代码)吗?如何将没有标头的请求发送到一台服务器,而将标头发送到另一台服务器?

以上是关于Angular资源如何保留ajax标头并同时启用cors的主要内容,如果未能解决你的问题,请参考以下文章

无法使用 cors 从 angular 2 获取所有响应标头

如何修复 Angular 1 + ajax + CORS 策略上的 No 'Access-Control-Allow-Origin' 标头? [复制]

如何在 Angular 2 中发出启用 CORS 的 HTTP 请求?

ProGuard - 如何保留方法并同时混淆它们?

如何在启用基本身份验证的情况下启用对 Web API 中所有来​​源的访问?

在进行 ajax 调用时在 HTTP 标头中包含 JWT