Usar un encabezado de autorización con Fetch en React Native

141

Estoy tratando de usar fetchReact Native para obtener información de la API de Product Hunt. Obtuve el token de acceso adecuado y lo guardé en estado, pero parece que no puedo pasarlo dentro del encabezado de autorización para una solicitud GET.

Esto es lo que tengo hasta ahora:

var Products = React.createClass({
  getInitialState: function() {
    return {
      clientToken: false,
      loaded: false
    }
  },
  componentWillMount: function () {
    fetch(api.token.link, api.token.object)
      .then((response) => response.json())
      .then((responseData) => {
          console.log(responseData);
        this.setState({
          clientToken: responseData.access_token,
        });
      })
      .then(() => {
        this.getPosts();
      })
      .done();
  },
  getPosts: function() {
    var obj = {
      link: 'https://api.producthunt.com/v1/posts',
      object: {
        method: 'GET',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json',
          'Authorization': 'Bearer ' + this.state.clientToken,
          'Host': 'api.producthunt.com'
        }
      }
    }
    fetch(api.posts.link, obj)
      .then((response) => response.json())
      .then((responseData) => {
        console.log(responseData);
      })
      .done();
  },

La expectativa que tengo para mi código es la siguiente:

  1. Primero, obtendré fetchun token de acceso con datos de mi módulo API importado
  2. Después de eso, estableceré la clientTokenpropiedad de this.stateigual al token de acceso recibido.
  3. Luego, ejecutaré lo getPostsque debería devolver una respuesta que contenga una serie de publicaciones actuales de Product Hunt.

Puedo verificar que el token de acceso se está recibiendo y que lo this.stateestá recibiendo como su clientTokenpropiedad. También puedo verificar que getPostsse está ejecutando.

El error que recibo es el siguiente:

{"error": "unauthorized_oauth", "error_description": "Proporcione un token de acceso válido. Consulte nuestra documentación de api sobre cómo autorizar una solicitud de api. Asegúrese también de que necesita los ámbitos correctos. Por ejemplo," público privado \ "para acceder a puntos finales privados".}

He estado trabajando bajo la suposición de que de alguna manera no estoy pasando el token de acceso correctamente en mi encabezado de autorización, pero parece que no puedo entender exactamente por qué.

Richard Kho
fuente
2
Como se señaló en este SO , los encabezados están destinados a ser minúsculas (algunos servidores respetan esto, otros no). Solo comparto porque me mordió porque no me conocía (y perdí el tiempo tratando de depurar el problema). Es lamentable que tantos proyectos, ejemplos y artículos no parecen respetar esto.
tj
@tj Los nombres de encabezado no distinguen entre mayúsculas y minúsculas, y eso es exactamente lo que dice la respuesta + aceptada en la pregunta que ha vinculado.
coreyward

Respuestas:

195

Ejemplo de búsqueda con encabezado de autorización:

fetch('URL_GOES_HERE', { 
   method: 'post', 
   headers: new Headers({
     'Authorization': 'Basic '+btoa('username:password'), 
     'Content-Type': 'application/x-www-form-urlencoded'
   }), 
   body: 'A=1&B=2'
 });
Cody Moniz
fuente
44
Esto no está funcionando para mí. El 'Authorization'encabezado silenciosamente no se puede adjuntar por firebug. Incluso he intentado incluirlo credentials: 'include'en el objeto opcional.
Ronnie Royston
77
@RonRoyston, ¿estás viendo la llamada de OPCIONES? si el punto final de la API no tiene CORS habilitado (Access-Control-Allow-Origin: * si accede desde un dominio diferente), entonces podría fallar en la llamada de OPTIONS.
Cody Moniz
1
el punto final de la API no tiene CORS habilitado, por eso probablemente no funcionó para mí. Gracias. Terminé instalando el complemento 'cors everywhere' para firefox y funcionó.
Ronnie Royston
3
En cuanto al problema que está viendo @RonRoyston, debe importar la biblioteca btoa , que no es nativa del nodo. (Es un puerto de una biblioteca de navegador). De lo contrario, la creación del encabezado de autenticación falla en silencio. Estábamos experimentando lo mismo.
Freewalker
2
developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch per docs, necesita envolver encabezados connew Headers()
Daniel Dubovski
67

Resulta que estaba usando el fetchmétodo incorrectamente.

fetch espera dos parámetros: un punto final para la API y un objeto opcional que puede contener cuerpo y encabezados.

Estaba envolviendo el objeto deseado dentro de un segundo objeto, lo que no me dio el resultado deseado.

Así es como se ve en un alto nivel:

fetch('API_ENDPOINT', OBJECT)  
  .then(function(res) {
    return res.json();
   })
  .then(function(resJson) {
    return resJson;
   })

Estructuré mi objeto como tal:

var obj = {  
  method: 'POST',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Origin': '',
    'Host': 'api.producthunt.com'
  },
  body: JSON.stringify({
    'client_id': '(API KEY)',
    'client_secret': '(API SECRET)',
    'grant_type': 'client_credentials'
  })
Richard Kho
fuente
¿podría quizás proporcionar el código que ahora funciona? Estoy tratando de usar fetch con un encabezado de autorización y no creo que mi código de autenticación se pase como encabezado, porque recibo una 401respuesta.
GoldenBeet
2
Hecho, espero que sea útil
Richard Kho
1
¡Oh, he estado en tu sitio personal con ese ejemplo! Así es como modelé el mío la primera vez. Sin embargo, descubrí mi problema, era solo que mi URL estaba equivocada. Se requería un /al final que me faltaba ...
GoldenBeet
1
Gracias, esto fue útil. Vale la pena señalar que, si bien la documentación de fetch señala que fetch no maneja las cookies, también puede agregar manualmente cookies al encabezado con este código. Simplemente guarde el uid y la clave y haga algo como: var obj = {método: 'GET', encabezados: {'Aceptar': 'application / json', 'Content-Type': 'application / json', 'Cookie': 'uid =' + uid + '; clave = '+ clave});
Dustin
8

Tuve este problema idéntico, estaba usando django-rest-knox para los tokens de autenticación. Resulta que nada estaba mal con mi método de búsqueda que se veía así:

...
    let headers = {"Content-Type": "application/json"};
    if (token) {
      headers["Authorization"] = `Token ${token}`;
    }
    return fetch("/api/instruments/", {headers,})
      .then(res => {
...

Estaba corriendo apache.

Lo resuelto este problema para mí fue cambiando WSGIPassAuthorizationa 'On'en wsgi.conf.

Tenía una aplicación Django implementada en AWS EC2, y usé Elastic Beanstalk para administrar mi aplicación, así que en el django.config, hice esto:

container_commands:
  01wsgipass:
    command: 'echo "WSGIPassAuthorization On" >> ../wsgi.conf'
Marquistador
fuente
0
completed = (id) => {
    var details = {
        'id': id,

    };

    var formBody = [];
    for (var property in details) {
        var encodedKey = encodeURIComponent(property);
        var encodedValue = encodeURIComponent(details[property]);
        formBody.push(encodedKey + "=" + encodedValue);
    }
    formBody = formBody.join("&");

    fetch(markcompleted, {
        method: 'POST',
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/x-www-form-urlencoded'
        },
        body: formBody
    })
        .then((response) => response.json())
        .then((responseJson) => {
            console.log(responseJson, 'res JSON');
            if (responseJson.status == "success") {
                console.log(this.state);
                alert("your todolist is completed!!");
            }
        })
        .catch((error) => {
            console.error(error);
        });
};
lilash sah
fuente