使用angular.js向HTTP请求添加自定义头部

91

我是一个 Angular.js 的初学者,我正在尝试向请求添加一些头部信息:

   var config = {headers: {
            'Authorization': 'Basic d2VudHdvcnRobWFuOkNoYW5nZV9tZQ==',
            'Accept': 'application/json;odata=verbose'
        }
    };

   $http.get('https://www.example.com/ApplicationData.svc/Malls(1)/Retailers', config).success(successCallback).error(errorCallback);

我已经查看了所有文档,这对我来说似乎应该是正确的。

当我在$http.get中使用本地文件作为URL时,我在Chrome的网络选项卡中看到以下HTTP请求:

GET /app/data/offers.json HTTP/1.1
Host: www.example.com
Connection: keep-alive
Cache-Control: max-age=0
If-None-Match: "0f0abc9026855b5938797878a03e6889"
Authorization: Basic Y2hhZHN0b25lbWFuOkNoYW5nZV9tZQ==
Accept: application/json;odata=verbose
X-Requested-With: XMLHttpRequest
If-Modified-Since: Sun, 24 Mar 2013 15:58:55 GMT
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22
X-Testing: Testing
Referer: http://www.example.com/app/index.html
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

正如您所看到的,这两个标题都已正确添加。但是当我将URL更改为上面$http.get中显示的地址(除了使用真实地址而不是example.com),我得到以下错误:

OPTIONS /ApplicationData.svc/Malls(1) HTTP/1.1
Host: www.datahost.net
Connection: keep-alive
Access-Control-Request-Method: GET
Origin: http://mpon.site44.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22
Access-Control-Request-Headers: accept, origin, x-requested-with, authorization, x-testing
Accept: */*
Referer: http://mpon.site44.com/app/index.html
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

这两者之间的代码唯一的区别在于第一个URL是本地文件,而第二个URL是远程服务器。如果您查看第二个请求头,会发现没有身份验证头,并且 Accept 使用的似乎是默认值而不是指定的值。另外,第一行现在显示为 OPTIONS 而不是 GET (尽管 Access-Control-Request-MethodGET)。

您有任何关于上面代码的问题或如何在不使用本地文件作为数据源时包含额外标头的想法吗?


2
这似乎是一个跨来源资源共享(CORS)问题 - 阅读此讨论以了解一些背景信息:https://groups.google.com/forum/#!topic/angular/CSBMY6oXfqs - Kevin Hakanson
确实是CORS问题。服务器未配置返回Access-Control-Allow-Origin:头文件。如果您想撰写一个包含评论和有关CORS的一些详细信息的答案,我会接受您的答案。 Dmitry Evseev下面的答案并经过您编辑是接近问题,但并不是真正的问题所在。 - trentclowater
1
Chrome会对跨域请求进行预检查以查找CORS头。请检查我的答案。 - Asim K T
9个回答

66

我使用了你提供的内容,并添加了另一个X-Testing头部

var config = {headers:  {
        'Authorization': 'Basic d2VudHdvcnRobWFuOkNoYW5nZV9tZQ==',
        'Accept': 'application/json;odata=verbose',
        "X-Testing" : "testing"
    }
};

$http.get("/test", config);

在Chrome的网络选项卡中,我可以看到它们正在被发送。

GET /test HTTP/1.1
Host: localhost:3000
Connection: keep-alive
Accept: application/json;odata=verbose
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22
Authorization: Basic d2VudHdvcnRobWFuOkNoYW5nZV9tZQ==
X-Testing: testing
Referer: http://localhost:3000/
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

你是在浏览器上看不到它们,还是在服务器上?尝试使用浏览器工具或调试代理,查看发送了什么。


我无法访问服务器,我正在使用Firefox浏览器,但我可以看到我在上面的原始问题中添加的标题。我不知道在Chrome的资源选项卡中哪里可以查看标题。 - trentclowater
抱歉,我在您的答案上添加了一个编辑,实际是应该添加在我的原始问题中。 - trentclowater
我的意思是开发工具的网络选项卡,而不是资源 - 更新回答。 - Kevin Hakanson
我在问题中添加了更多信息。看起来标题在某些情况下已经被添加,但在另一种情况下没有被添加。 - trentclowater

21

使用HTTP POST方法进行基本身份验证:

$http({
    method: 'POST',
    url: '/API/authenticate',
    data: 'username=' + username + '&password=' + password + '&email=' + email,
    headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        "X-Login-Ajax-call": 'true'
    }
}).then(function(response) {
    if (response.data == 'ok') {
        // success
    } else {
        // failed
    }
});

...以及带有头部信息的GET方法调用:

$http({
    method: 'GET',
    url: '/books',
    headers: {
        'Authorization': 'Basic d2VudHdvcnRobWFuOkNoYW5nZV9tZQ==',
        'Accept': 'application/json',
        "X-Login-Ajax-call": 'true'
    }
}).then(function(response) {
    if (response.data == 'ok') {
        // success
    } else {
        // failed
    }
});

最佳答案。 - Yoda

9

如果您想将自定义标头添加到所有请求中,您可以更改$httpProvider上的默认设置以始终添加此标头...

app.config(['$httpProvider', function ($httpProvider) {
    $httpProvider.defaults.headers.common = { 
        'Authorization': 'Basic d2VudHdvcnRobWFuOkNoYW5nZV9tZQ==',
        'Accept': 'application/json;odata=verbose'
      };
}]);

除了OPTIONS请求之外的所有请求 - Rocco
不错的例子。这个可以用来缓存重定向页面的令牌吗? - MartianMartian

7
我的建议是添加一个这样的函数设置: 在函数内部检查适合它的标题。 我相信它一定会起作用。对我来说,它完美地运作着。
function getSettings(requestData) {
    return {
        url: requestData.url,
        dataType: requestData.dataType || "json",
        data: requestData.data || {},
        headers: requestData.headers || {
            "accept": "application/json; charset=utf-8",
            'Authorization': 'Bearer ' + requestData.token
        },
        async: requestData.async || "false",
        cache: requestData.cache || "false",
        success: requestData.success || {},
        error: requestData.error || {},
        complete: requestData.complete || {},
        fail: requestData.fail || {}
    };
}

然后按照以下方式调用您的数据:
    var requestData = {
        url: 'API end point',
        data: Your Request Data,
        token: Your Token
    };

    var settings = getSettings(requestData);
    settings.method = "POST"; //("Your request type")
    return $http(settings);

2
你看到的OPTIONS请求是正常的,但它没有暴露授权头。为了使基本身份验证起作用,你需要在var config中添加:withCredentials = true;

来自AngularJS $http文档

withCredentials - {boolean} - 是否在XHR对象上设置withCredentials标志。有关更多信息,请参见带凭据的请求


1
Chrome会对请求进行预检查以查找CORS头。如果请求可接受,它将发送真正的请求。如果您在跨域操作中这样做,您只需处理它,否则找到一种使请求非跨域的方法。这是按设计来实现的。
与上面讨论的简单请求不同,“预检”请求首先通过OPTIONS方法向其他域上的资源发送HTTP请求,以确定实际请求是否安全发送。由于跨站点请求可能对用户数据产生影响,因此会像这样进行预检。特别地,如果请求:
- 使用除GET、HEAD或POST之外的方法。此外,如果使用POST将请求数据发送到Content-Type为application/x-www-form-urlencoded、multipart/form-data或text/plain以外的内容类型(例如,如果POST请求使用application/xml或text/xml向服务器发送XML有效负载),则该请求将进行预检。 - 在请求中设置自定义标头(例如,请求使用诸如X-PINGOTHER之类的标头)

参考:Chrome中的AJAX发送OPTIONS而不是GET/POST/PUT/DELETE?


1
服务器的回复是什么?它应该回复 204 然后真正发送你所请求的 GET。
在 OPTIONS 中,客户端检查服务器是否允许 CORS 请求。如果它给你的不是 204,则应配置服务器以发送正确的 Allow-Origin 标头。
你添加标头的方式是正确的。

0

你只是在添加一个服务器不允许的头部信息。

例如 - 你的服务器设置了CORS,只允许这些头部信息(accept、cache-control、pragma、content-type、origin)

而在你的HTTP请求中,你却添加了如下内容:

 headers: {
        'Authorization': 'Basic d2VudHdvcnRobWFuOkNoYW5nZV9tZQ==',
        'Accept': 'application/json',
        'x-testing': 'testingValue'
    }

如果请求中包含了(Authorization 和 x-testing)字段,那么服务器将拒绝该请求,因为这些字段不被允许。

这是服务器端的配置。

与 HTTP Options 没有任何关系,这只是来自不同域的预检请求,用于检查服务器是否允许实际调用。


-9

对我来说,以下的解释片段很有用。也许你不应该在标题名称中使用'

{
   headers: { 
      Authorization: "Basic " + getAuthDigest(), 
      Accept: "text/plain" 
   }
}

我正在使用$http.ajax(),但我不认为这会改变游戏规则。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接