Agregar un encabezado personalizado a la solicitud HTTP usando angular.js

89

Soy un novato en angular.js y estoy tratando de agregar algunos encabezados a una solicitud:

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

He mirado toda la documentación y me parece que debería ser correcta.

Cuando utilizo un archivo local para la URL en el $http.get, veo la siguiente solicitud HTTP en la pestaña de red en 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 puede ver, ambos encabezados se agregaron correctamente. Pero cuando cambio la URL a la que se muestra $http.getarriba (excepto usando la dirección real, no example.com), obtengo:

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

La única diferencia de código entre estos dos es que, para el primero, la URL es un archivo local y, para el segundo, la URL es un servidor remoto. Si observa el segundo encabezado de Solicitud, no hay un encabezado de Autenticación y Acceptparece estar usando un encabezado predeterminado en lugar del especificado. Además, la primera línea ahora dice en OPTIONSlugar de GET(aunque Access-Control-Request-Methodes GET).

¿Alguna idea de lo que está mal con el código anterior, o cómo obtener los encabezados adicionales incluidos cuando no se usa un archivo local como fuente de datos?

trentclowater
fuente
2
Esto parece un problema de CORS. Lea esta discusión para conocer algunos antecedentes: groups.google.com/forum/#!topic/angular/CSBMY6oXfqs
Kevin Hakanson
De hecho, fue un problema de CORS. El servidor no estaba configurado para devolver el encabezado Access-Control-Allow-Origin :. Si desea escribir una respuesta con su comentario y un poco de detalle sobre CORS, aceptaré su respuesta. La respuesta a continuación de Dmitry Evseev y editada por usted estuvo cerca, pero no es realmente el problema real.
trentclowater
1
Chrome está realizando una verificación previa de la solicitud para buscar encabezados CORS si la solicitud es de dominio cruzado. Comprueba mi respuesta.
Asim KT

Respuestas:

66

Tomé lo que tenías y agregué otro X-Testingencabezado

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

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

Y en la pestaña de red de Chrome, veo que se envían.

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

¿No los ve desde el navegador o en el servidor? Pruebe las herramientas del navegador o un proxy de depuración y vea lo que se envía.

Kevin Hakanson
fuente
No tengo acceso al servidor y en el navegador estoy usando Firefox, pero veo los encabezados que agregué a la pregunta original anterior. No veo dónde puede ver los encabezados en la pestaña de recursos en Chrome.
trentclowater
Lo siento, agregué una edición a su respuesta que debía incluirse en mi pregunta original.
trentclowater
Me refiero a la pestaña de red de las herramientas para desarrolladores, no a los recursos - Respuesta de actualizaciones
Kevin Hakanson
Agregué más información a la pregunta. Parece que los encabezados se agregan en un caso, pero no en otro.
trentclowater
21

Autenticación básica mediante el 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
    }
});

... y llamada al método GET con encabezado:

$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
fuente
La mejor respuesta.
Yoda
9

Si desea agregar sus encabezados personalizados a TODAS las solicitudes, puede cambiar los valores predeterminados en $ httpProvider para agregar siempre este encabezado ...

app.config(['$httpProvider', function ($httpProvider) {
    $httpProvider.defaults.headers.common = { 
        'Authorization': 'Basic d2VudHdvcnRobWFuOkNoYW5nZV9tZQ==',
        'Accept': 'application/json;odata=verbose'
      };
}]);
Korayem
fuente
TODAS excepto OPCIONES solicita que sea
Rocco
buen ejemplo. ¿Se puede usar para almacenar en caché el token para redirigir páginas?
Martian2049
7

Mi sugerencia será agregar una configuración de llamada de función como esta dentro de la función, verifique el encabezado que sea apropiado para ella. Estoy seguro de que definitivamente funcionará. funciona perfectamente para mí.

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

luego llama a tus datos así

    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
fuente
2

Lo que ves para la solicitud de OPCIONES está bien. Los encabezados de autorización no están expuestos en él.

Pero para que la autenticación básica funcione, debe agregar: withCredentials = true;a su var config.

De la documentación de AngularJS $ http :

withCredentials - {boolean}- si se debe establecer la withCredentials bandera en el objeto XHR. Consulte las solicitudes con credenciales para obtener más información.

Dmitry Evseev
fuente
1

¿Y cuál es la respuesta del servidor? Debería responder un 204 y luego enviar realmente el GET que está solicitando.

En las OPCIONES, el cliente está comprobando si el servidor permite solicitudes CORS. Si te da algo diferente a 204, entonces debes configurar tu servidor para enviar los encabezados de Allow-Origin correctos.

La forma en que agrega encabezados es la forma correcta de hacerlo.

barra fantasma
fuente
1

Chrome está realizando una verificación previa de la solicitud para buscar encabezados CORS. Si la solicitud es aceptable, enviará la solicitud real. Si está haciendo este dominio cruzado, simplemente tendrá que lidiar con él o, de lo contrario, encontrará una manera de hacer que la solicitud no sea de dominio cruzado. Esto es por diseño.

A diferencia de las solicitudes simples (discutidas anteriormente), las solicitudes de "verificación previa" envían primero una solicitud HTTP mediante el método OPTIONS al recurso en el otro dominio, para determinar si la solicitud real es segura de enviar. Las solicitudes entre sitios se revisan previamente de esta manera, ya que pueden tener implicaciones en los datos del usuario. En particular, una solicitud tiene una verificación previa si:

Utiliza métodos distintos a GET, HEAD o POST. Además, si se usa POST para enviar datos de solicitud con un tipo de contenido que no sea application / x-www-form-urlencoded, multipart / form-data o text / plain, por ejemplo, si la solicitud POST envía una carga útil XML al servidor usando application / xml o text / xml, la solicitud tiene una verificación previa. Establece encabezados personalizados en la solicitud (por ejemplo, la solicitud utiliza un encabezado como X-PINGOTHER)

Ref: AJAX en Chrome enviando OPCIONES en lugar de GET / POST / PUT / DELETE?

Asim KT
fuente
-8

Para mí, el siguiente fragmento explicativo funcionó. ¿Quizás no debería usar 'para el nombre del encabezado?

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

Estoy usando $http.ajax(), aunque no esperaría que eso cambiara las reglas del juego.

ŁukaszBachman
fuente