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

我是 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中显示的 URL (除了使用实际地址,而不是 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)。

知道上面的代码出了什么问题吗? 或者在不使用本地文件作为数据源时,如何获得包含的附加头文件?

237466 次浏览

For me the following explanatory snippet worked. Perhaps you shouldn't use ' for header name?

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

I'm using $http.ajax(), though I wouldn't expect that to be a game changer.

I took what you had, and added another X-Testing header

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


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

And in the Chrome network tab, I see them being sent.

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

Are you not seeing them from the browser, or on the server? Try the browser tooling or a debug proxy and see what is being sent out.

What you see for OPTIONS request is fine. Authorisation headers are not exposed in it.

But in order for basic auth to work you need to add: withCredentials = true; to your var config.

From the AngularJS $http documentation:

withCredentials - {boolean} - whether to to set the withCredentials flag on the XHR object. See requests with credentials for more information.

And what's the answer from the server? It should reply a 204 and then really send the GET you are requesting.

In the OPTIONS the client is checking if the server allows CORS requests. If it gives you something different than a 204 then you should configure your server to send the correct Allow-Origin headers.

The way you are adding headers is the right way to do it.

my suggestion will be add a function call settings like this inside the function check the header which is appropriate for it. I am sure it will definitely work. it is perfectly working for me.

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 || {}
};
}

then call your data like this

    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);

If you want to add your custom headers to ALL requests, you can change the defaults on $httpProvider to always add this header…

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

Basic authentication using HTTP POST method:

$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
}
});

...and GET method call with header:

$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
}
});

Chrome is preflighting the request to look for CORS headers. If the request is acceptable, it will then send the real request. If you're doing this cross-domain, you will simply have to deal with it or else find a way to make the request non-cross-domain. This is by design.

Unlike simple requests (discussed above), "preflighted" requests first send an HTTP request by the OPTIONS method to the resource on the other domain, in order to determine whether the actual request is safe to send. Cross-site requests are preflighted like this since they may have implications to user data. In particular, a request is preflighted if:

It uses methods other than GET, HEAD or POST. Also, if POST is used to send request data with a Content-Type other than application/x-www-form-urlencoded, multipart/form-data, or text/plain, e.g. if the POST request sends an XML payload to the server using application/xml or text/xml, then the request is preflighted. It sets custom headers in the request (e.g. the request uses a header such as X-PINGOTHER)

Ref: AJAX in Chrome sending OPTIONS instead of GET/POST/PUT/DELETE?

You are just adding a header which server does not allow.

eg - your server is set up CORS to allow these headers only (accept,cache-control,pragma,content-type,origin)

and in your http request you are adding like this

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

then the Server will reject this request since (Authorization and x-testing) are not allowed.

This is server side configuration.

And there is nothing to do with HTTP Options, it is just a preflight to server which is from different domain to check if server will allow actual call or not.