es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Forzar la codificación de texto plano en una solicitud de obtención de HTTPS en Node.

Problema

Relacionado con Obtener contenido HTML UTF-8 con http.get de Node – pero esa respuesta no está funcionando para mí.

Estoy tratando de llamar al endpoint de preguntas de la API de Stack Overflow:

none
https://api.stackexchange.com/2.3/questions?site=stackoverflow&filter=total

Lo cual debería devolver la siguiente respuesta JSON:

json
{"total":21951385}

Código de Ejemplo

Estoy usando el módulo de Node https para enviar una solicitud get de la siguiente manera:

const getRequest = (url: string) => new Promise((resolve, reject) => {
    const options: RequestOptions = {
        headers: {
            'Accept': 'text/*',
            'Accept-Encoding':'identity',
            'Accept-Charset' : 'utf8',
        }
    }

<pre><code>const req = get(url, options, (res) => {
    res.setEncoding('utf8');
    let responseBody = '';
    res.on('data', (chunk) => responseBody += chunk);
    res.on('end', () => resolve(responseBody));
});

req.on('error', (err) => reject(err));
req.end();
</code></pre>

})

Y luego lo llamo de la siguiente manera:

ts
const questionsUrl = 'https://api.stackexchange.com/2.3/questions?&site=stackoverflow&filter=total'
const resp = await getRequest(questionsUrl)
console.log(resp)

Sin embargo, obtengo la respuesta:

none
▼�
�V*�/I�Q�22�454�0�♣��♥‼���↕

Lo que he intentado

He intentado varias variaciones de lo siguiente:

  • Estoy llamando setEncoding a utf8 en el flujo
  • He configurado el encabezado Accept a text/* – lo cual

    > Proporciona un tipo MIME de texto, pero sin un subtipo

  • He configurado el encabezado Accept-Encoding a identity – lo cual

    > Indica la función de identidad (es decir, sin modificación o compresión)

Este código también funciona perfectamente con prácticamente cualquier otro servidor API, por ejemplo, usando la siguiente URL:

none
https://jsonplaceholder.typicode.com/todos/1

Pero la API de StackOverflow funciona en cualquier otro lugar que haya intentado, por lo que debe haber una manera de instruir a Node cómo ejecutarla.

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Solución

    El problema con el código actual es que la respuesta de la API de Stack Overflow está comprimida con gzip, lo que significa que debe ser descomprimida antes de poder ser analizada como contenido UTF-8.

    Para solucionar esto, necesitamos actualizar la función getRequest para manejar la compresión gzip configurando el encabezado Accept-Encoding en gzip y usando el módulo zlib para descomprimir la respuesta:

    const { get } = require('https');
    const zlib = require('zlib');
    
    const getRequest = (url: string) => new Promise((resolve, reject) => {
      const options = {
        headers: {
          'Accept-Encoding': 'gzip',
        }
      };
    
      const req = get(url, options, (res) => {
        let responseBody;
    
        if (res.headers['content-encoding'] === 'gzip') {
          const gzip = zlib.createGunzip();
          res.pipe(gzip);
          responseBody = gzip;
        } else {
          responseBody = res;
        }
    
        responseBody.setEncoding('utf8');
        let buffer = '';
        responseBody.on('data', (data) => buffer += data);
        responseBody.on('end', () => resolve(buffer));
      });
    
      req.on('error', (err) => reject(err));
      req.end();
    });
    
    const questionsUrl = 'https://api.stackexchange.com/2.3/questions?&site=stackoverflow&filter=total';
    const resp = await getRequest(questionsUrl);
    console.log(resp); // outputs {"total":21951385}
    

    La función getRequest actualizada verifica si la respuesta está comprimida con gzip mirando el encabezado content-encoding de la respuesta. Si está comprimida con gzip, crea un flujo de transformación zlib.createGunzip() para descomprimir la respuesta. Se llama a setEncoding('utf8') en la respuesta descomprimida, y se concatena la respuesta en un búfer usando el evento data. El búfer se resuelve una vez que se dispara el evento end.

    Con estos cambios, la respuesta de la API debería ser descomprimida correctamente y devuelta como una cadena, que luego se puede analizar como JSON.

Comments are closed.