Adicionar um cabeçalho personalizado à solicitação HTTP usando angular.js

89

Sou um novato no angular.js e estou tentando adicionar alguns cabeçalhos a uma solicitação:

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

Eu olhei toda a documentação, e isso me parece que deveria estar correto.

Quando eu uso um arquivo local para o URL no $http.get, vejo a seguinte solicitação HTTP na guia de rede no Chrome:

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

Como você pode ver, os dois cabeçalhos foram adicionados corretamente. Mas quando eu mudo o URL para aquele mostrado $http.getacima (exceto usando o endereço real, não example.com), então obtenho:

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

A única diferença de código entre os dois é que, para o primeiro, o URL é um arquivo local e, para o segundo, o URL é um servidor remoto. Se você olhar o segundo cabeçalho de Solicitação, não há cabeçalho de Autenticação e o Acceptparece estar usando um padrão em vez do especificado. Além disso, a primeira linha agora diz em OPTIONSvez de GET(embora Access-Control-Request-Methodseja GET).

Alguma ideia do que há de errado com o código acima, ou como obter os cabeçalhos adicionais incluídos usando quando não estiver usando um arquivo local como fonte de dados?

trentclowater
fonte
2
Isso parece um problema do CORS - leia esta discussão para obter alguns antecedentes: groups.google.com/forum/#!topic/angular/CSBMY6oXfqs
Kevin Hakanson
Era realmente um problema do CORS. O servidor não foi configurado para retornar o cabeçalho Access-Control-Allow-Origin :. Se você quiser escrever uma resposta com seu comentário e um pouco de detalhe sobre o CORS, aceitarei sua resposta. A resposta abaixo, de Dmitry Evseev e editada por você, chegou perto, mas não era exatamente o problema real.
trentclowater
1
O Chrome está testando a solicitação para procurar cabeçalhos CORS se a solicitação for entre domínios. Verifique minha resposta.
Asim KT

Respostas:

66

Peguei o que você tinha e adicionei outro X-Testingcabeçalho

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

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

E na guia da rede do Chrome, eu os vejo sendo enviados.

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

Você não os está vendo no navegador ou no servidor? Experimente as ferramentas do navegador ou um proxy de depuração e veja o que está sendo enviado.

Kevin Hakanson
fonte
Não tenho acesso ao servidor e no navegador estou usando o Firefox, mas estou vendo os cabeçalhos que adicionei à pergunta original acima. Não vejo onde você pode visualizar os cabeçalhos na guia de recursos no Chrome.
trentclowater
Desculpe, adicionei uma edição à sua resposta que deveria ir na minha pergunta original.
trentclowater
Eu quis dizer a guia de rede das ferramentas do desenvolvedor, não recursos - resposta de atualizações
Kevin Hakanson
Eu adicionei mais informações à pergunta. Parece que os cabeçalhos são adicionados em um caso, mas não em outro.
trentclowater
21

Autenticação básica usando o método 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
    }
});

... e chamada de método GET com cabeçalho:

$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
    }
});
Ajay Kumar
fonte
A melhor resposta.
Yoda
9

Se você quiser adicionar seus cabeçalhos personalizados a TODAS as solicitações, você pode alterar os padrões em $ httpProvider para sempre adicionar este cabeçalho ...

app.config(['$httpProvider', function ($httpProvider) {
    $httpProvider.defaults.headers.common = { 
        'Authorization': 'Basic d2VudHdvcnRobWFuOkNoYW5nZV9tZQ==',
        'Accept': 'application/json;odata=verbose'
      };
}]);
Korayem
fonte
TODAS as solicitações, exceto OPTIONS
Rocco
bom exemplo. isso pode ser usado para armazenar token em cache para redirecionar páginas?
Martian2049
7

minha sugestão será adicionar uma configuração de chamada de função como esta dentro da função verificar o cabeçalho que é apropriado para ela. Tenho certeza que definitivamente funcionará. está funcionando perfeitamente para mim.

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

então chame seus dados assim

    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);
Riyadh Ul Islam
fonte
2

O que você vê para a solicitação de OPÇÕES está bom. Os cabeçalhos de autorização não são expostos nele.

Mas para que a autenticação básica funcione, você precisa adicionar: withCredentials = true;ao seu var config.

Da documentação $ http do AngularJS :

withCredentials - {boolean}- se deve definir a withCredentials bandeira no objeto XHR. Veja as solicitações com credenciais para mais informações.

Dmitry Evseev
fonte
1

E qual é a resposta do servidor? Ele deve responder um 204 e então realmente enviar o GET que você está solicitando.

Em OPÇÕES o cliente está verificando se o servidor permite solicitações CORS. Se ele fornecer algo diferente de 204, você deve configurar seu servidor para enviar os cabeçalhos Allow-Origin corretos.

A maneira como você adiciona cabeçalhos é a maneira certa de fazer isso.

ghostbar
fonte
1

O Chrome está testando a solicitação para procurar cabeçalhos CORS. Se a solicitação for aceitável, ele enviará a solicitação real. Se estiver fazendo isso entre domínios, você simplesmente terá que lidar com isso ou então encontrar uma maneira de tornar a solicitação não entre domínios. Isso ocorre por design.

Ao contrário das solicitações simples (discutidas acima), as solicitações "preflighted" enviam primeiro uma solicitação HTTP pelo método OPTIONS para o recurso no outro domínio, a fim de determinar se a solicitação real é segura para envio. As solicitações entre sites são verificadas dessa forma, pois podem ter implicações nos dados do usuário. Em particular, uma solicitação é testada se:

Ele usa métodos diferentes de GET, HEAD ou POST. Além disso, se POST for usado para enviar dados de solicitação com um tipo de conteúdo diferente de application / x-www-form-urlencoded, multipart / form-data ou text / plain, por exemplo, se a solicitação POST enviar uma carga XML para o servidor usando application / xml ou text / xml, a solicitação é testada. Ele define cabeçalhos personalizados na solicitação (por exemplo, a solicitação usa um cabeçalho como X-PINGOTHER)

Ref: AJAX no Chrome enviando OPÇÕES em vez de GET / POST / PUT / DELETE?

Asim KT
fonte
-8

Para mim, o seguinte fragmento explicativo funcionou. Talvez você não deva usar 'para o nome do cabeçalho?

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

Estou usando $http.ajax(), embora não espere que isso mude o jogo.

ŁukaszBachman
fonte