web-dev-qa-db-fra.com

"Jeton inattendu dans JSON à la position 0" en utilisant JSON.parse dans Node avec JSON valide

Cela fait des heures que je m'arrache les cheveux sur celui-ci.

J'ai un simple serveur Node qui fait un appel à une API externe pour obtenir un bit (massif, comme 4+ Mo) de JSON. J'utilise à peu près autant de réponses standard que possible get, extrait directement des documents Node:

const muniURL = `http://api.511.org/transit/vehiclemonitoring?api_key=${API_KEYS.API_KEY_511}&format=json&agency=sf-muni`;

http.get(muniURL, (res) => {
  const statusCode = res.statusCode;
  const contentType = res.headers['content-type'];
  console.log('Status Code:', statusCode);
  console.log('Content Type:', contentType);

  let error;
  if (statusCode !== 200) {
    error = new Error(`Request Failed.\n` +
                      `Status Code: ${statusCode}`);
  } else if (!/^application\/json/.test(contentType)) {
    error = new Error(`Invalid content-type.\n` +
                      `Expected application/json but received ${contentType}`);
  }
  if (error) {
    console.log(`Request error: ${error.message}`);
    // consume response data to free up memory
    res.resume();
    return;
  }

  res.setEncoding('utf8');
  let rawData = '';
  res.on('data', (chunk) => rawData += chunk);
  res.on('end', () => {
    try {
      const parsedData = JSON.parse(rawData);
      console.log('parsedData:', parsedData);
    } catch (e) {
      console.log(`Caught error: ${e.message}`);
    }
  });
}).on('error', (e) => {
  console.log(`Got error: ${e.message}`);
});

... et à chaque fois, il frappe l'instruction catch avec: Caught error: Unexpected token in JSON at position 0. (Notez les deux espaces entre 'token' et 'in'.)

J'ai vérifié le JSON renvoyé par les deux Chrome et Postman avec deux validateurs JSON basés sur le Web différents, et il revient comme valide. Tout en écrivant rawData dans un fichier ressemble à quelque chose comme un tampon (?) ...

1fef bfbd 0800 0000 0000 0400 efbf bdef
bfbd efbf bd72 efbf bdc8 b62d efbf bd2b
0c3f 7547 1cef bfbd 00ef bfbd efbf bd0b
efbf bd5b 49ef bfbd 2def bfbd 6c6b efbf
bd5c 55ef bfbd efbf bd44 3fef bfbd 126c
71ef bfbd 021c 2029 6def bfbd 13ef bfbd
efbf bdef bfbd 437f 52ef bfbd 4227 48ef
bfbd efbf bd4d efbf bd31 13ef bfbd 09ef
bfbd 5d2f 7bef bfbd efbf bde5 aa81 745e
efbf bd65 efbf bd31 efbf bdef bfbd efbf
...

...Buffer.isBuffer revient faux.

Jusqu'à présent, j'ai essayé JSON.stringifying en premier, toStringing, conversion en new Buffer, puis la chaîne, .triming espace blanc, et replaceing toutes sortes de caractères d'échappement, en vain.

Qu'est-ce que j'oublie ici?


EDIT: J'ai réalisé que je validais JSON récupéré par Chrome et Postman, qui font apparemment un prétraitement quelconque. curling l'URL génère tout un tas de désordre ce n'est certainement pas du JSON. Reste toujours aux questions de quel type de données ce désordre est réellement, et pourquoi je n'obtiens pas le JSON quand je le demande spécifiquement.

7
dangerismycat

Il semble que api.511.org applique gzip à tous les appels api qui fournissent une api_key valide. Il renvoie également un premier caractère non valide dans la réponse json.

Voici une solution de contournement:

var request = require('request');

var apiUrl = 'http://api.511.org/transit/vehiclemonitoring?api_key=${API_KEYS.API_KEY_511}&format=json&agency=sf-muni';
//apiUrl = 'http://ip.jsontest.com/';

var response = request({
    method: 'GET',
    uri: apiUrl,
    gzip: true
}, function(error, response, body) {
    //* workaround for issue with this particular apiUrl
    var firstChar = body.substring(0, 1);
    var firstCharCode = body.charCodeAt(0);
    if (firstCharCode == 65279) {
        console.log('First character "' + firstChar + '" (character code: ' + firstCharCode + ') is invalid so removing it.');
        body = body.substring(1);
    }
    //*/

    var parsedJson = JSON.parse(body);
    console.log('parsedJson: ', parsedJson);
});
11
Rocky Sims