Solicitud HTTP GET en Node.js Express

191

¿Cómo puedo hacer una solicitud HTTP desde Node.js o Express.js? Necesito conectarme a otro servicio. Espero que la llamada sea asíncrona y que la devolución de llamada contenga la respuesta del servidor remoto.

Travis Parks
fuente

Respuestas:

219

Aquí hay un fragmento de algún código de una muestra mía. Es asíncrono y devuelve un objeto JSON. Puede hacer cualquier tipo de solicitud GET.

Tenga en cuenta que hay formas más óptimas (solo una muestra), por ejemplo, en lugar de concatenar los fragmentos que coloca en una matriz y unirlos, etc. Esperemos que comience en la dirección correcta:

const http = require('http');
const https = require('https');

/**
 * getJSON:  RESTful GET request returning JSON object(s)
 * @param options: http options object
 * @param callback: callback to pass the results JSON object(s) back
 */

module.exports.getJSON = (options, onResult) => {
  console.log('rest::getJSON');
  const port = options.port == 443 ? https : http;

  let output = '';

  const req = port.request(options, (res) => {
    console.log(`${options.host} : ${res.statusCode}`);
    res.setEncoding('utf8');

    res.on('data', (chunk) => {
      output += chunk;
    });

    res.on('end', () => {
      let obj = JSON.parse(output);

      onResult(res.statusCode, obj);
    });
  });

  req.on('error', (err) => {
    // res.send('error: ' + err.message);
  });

  req.end();
};

Se llama creando un objeto de opciones como:

const options = {
  host: 'somesite.com',
  port: 443,
  path: '/some/path',
  method: 'GET',
  headers: {
    'Content-Type': 'application/json'
  }
};

Y proporcionando una función de devolución de llamada.

Por ejemplo, en un servicio, requiero el módulo REST anterior y luego hago esto:

rest.getJSON(options, (statusCode, result) => {
  // I could work with the resulting HTML/JSON here. I could also just return it
  console.log(`onResult: (${statusCode})\n\n${JSON.stringify(result)}`);

  res.statusCode = statusCode;

  res.send(result);
});

ACTUALIZAR

Si está buscando async/ await(lineal, sin devolución de llamada), promesas, soporte de tiempo de compilación e inteligencia, creamos un cliente HTTP y REST liviano que se ajusta a esa factura:

Microsoft escribió-rest-client

Bryanmac
fuente
@bryanmac, ¿puede enviar / agregar la muestra completa?
StErMi
@bryanmac con su permiso Me gustaría usar este plugin de código gruñido que estoy construyendo actualmente. No estoy seguro de cuándo, pero se haría de código abierto cuando se complete.
JeffH
3
intente el módulo de solicitud ... es mucho más simple sitepoint.com/making-http-requests-in-node-js
saurshaz
66
sí, el módulo de solicitud es simple pero este es un nivel inferior que muestra lo que está haciendo bibliotecas como el módulo de solicitud. Si necesita control de nivel inferior o solicitudes http (que muestran el progreso en descargas grandes, etc.), esto muestra cómo se hace.
bryanmac
1
@KrIsHnA: el nodo tiene un objeto de cadena de consulta: nodejs.org/api/querystring.html y el objeto de url nodejs.org/docs/latest/api/url.html
bryanmac
100

Intente usar la http.get(options, callback)función simple en node.js:

var http = require('http');
var options = {
  host: 'www.google.com',
  path: '/index.html'
};

var req = http.get(options, function(res) {
  console.log('STATUS: ' + res.statusCode);
  console.log('HEADERS: ' + JSON.stringify(res.headers));

  // Buffer the body entirely for processing as a whole.
  var bodyChunks = [];
  res.on('data', function(chunk) {
    // You can process streamed parts here...
    bodyChunks.push(chunk);
  }).on('end', function() {
    var body = Buffer.concat(bodyChunks);
    console.log('BODY: ' + body);
    // ...and/or process the entire body here.
  })
});

req.on('error', function(e) {
  console.log('ERROR: ' + e.message);
});

También hay una http.request(options, callback)función general que le permite especificar el método de solicitud y otros detalles de la solicitud.

maerics
fuente
¿Dónde está el contenido de la respuesta del servidor que solicitó el OP?
Dan Dascalescu
Gracias por la actualización. Parece que hay una necesidad de un controlador 'final' para concatenar los trozos entonces. ¿Qué equivale básicamente a la respuesta de @ bryanmac?
Dan Dascalescu
@DanDascalescu: sí, si quieres procesar el cuerpo como un todo (lo que es probable), entonces probablemente quieras almacenarlo en el búfer y procesarlo al 'final'. Actualizaré mi respuesta también para completar.
Maerics
lo siento, no puedo entender con qué parámetros se llama a la devolución de llamada ... cómo puedo obtener el cuerpo y dónde está la referencia para los parámetros y las propiedades de esos parámetros.
Muhammad Umer
@maerics ¿Cómo puedo usar esta GETsolicitud si tengo esta URL? graph.facebook.com/debug_token? input_token={token-to-inspect} &access_token={app-token-or-admin-token}?
frank17
70

Request y Superagent son bibliotecas bastante buenas para usar.

nota: la solicitud está en desuso , ¡use bajo su responsabilidad!

Utilizando request:

var request=require('request');

request.get('https://someplace',options,function(err,res,body){
  if(err) //TODO: handle err
  if(res.statusCode === 200 ) //etc
  //TODO Do something with response
});
staackuser2
fuente
77
¿Debería ser res.statusCode === 200 en segundo si? )
Gleb Dolzikov
1
¿Cuál es la variable de opciones? solo pasa uno indefinido? lo dudo
lxknvlk
32

También puede usar Requestify , un cliente HTTP realmente genial y muy simple que escribí para nodeJS + que admite el almacenamiento en caché.

Simplemente haga lo siguiente para la solicitud del método GET:

var requestify = require('requestify');

requestify.get('http://example.com/api/resource')
  .then(function(response) {
      // Get the response body (JSON parsed or jQuery object for XMLs)
      response.getBody();
  }
);
ranm8
fuente
1
"Probar esta otra herramienta" no es una respuesta aceptable si el conjunto de herramientas existente es suficiente.
Grunion Shaftoe
9

Esta versión se basa en la función inicialmente propuesta por bryanmac que utiliza promesas, mejor manejo de errores y se reescribe en ES6.

let http = require("http"),
    https = require("https");

/**
 * getJSON:  REST get request returning JSON object(s)
 * @param options: http options object
 */
exports.getJSON = function(options)
{
    console.log('rest::getJSON');
    let reqHandler = +options.port === 443 ? https : http;

    return new Promise((resolve, reject) => {
        let req = reqHandler.request(options, (res) =>
        {
            let output = '';
            console.log('rest::', options.host + ':' + res.statusCode);
            res.setEncoding('utf8');

            res.on('data', function (chunk) {
                output += chunk;
            });

            res.on('end', () => {
                try {
                    let obj = JSON.parse(output);
                    // console.log('rest::', obj);
                    resolve({
                        statusCode: res.statusCode,
                        data: obj
                    });
                }
                catch(err) {
                    console.error('rest::end', err);
                    reject(err);
                }
            });
        });

        req.on('error', (err) => {
            console.error('rest::request', err);
            reject(err);
        });

        req.end();
    });
};

Como resultado, no tiene que pasar una función de devolución de llamada, sino que getJSON () devuelve una promesa. En el siguiente ejemplo, la función se usa dentro de un controlador de ruta ExpressJS

router.get('/:id', (req, res, next) => {
    rest.getJSON({
        host: host,
        path: `/posts/${req.params.id}`,
        method: 'GET'
    }).then(({status, data}) => {
        res.json(data);
    }, (error) => {
        next(error);
    });
});

En caso de error, delega el error en el servidor que maneja el middleware.

maqduni
fuente
1
Sí, este ejemplo muestra cómo hacerlo dentro de una getdefinición de ruta Express , de la que carecen muchas publicaciones aquí.
Micros
7

Unirest es la mejor biblioteca que he encontrado para realizar solicitudes HTTP desde Node. Su objetivo es ser un marco multiplataforma, por lo que aprender cómo funciona en Node le servirá bien si necesita usar un cliente HTTP en Ruby, PHP, Java, Python, Objective C, .Net o Windows 8 también. Hasta donde puedo decir, las bibliotecas de inquietudes están respaldadas principalmente por clientes HTTP existentes (por ejemplo, en Java, el cliente Apache HTTP, en Node, la biblioteca de solicitud de Mikeal ): Unirest simplemente pone una API más agradable en la parte superior.

Aquí hay un par de ejemplos de código para Node.js:

var unirest = require('unirest')

// GET a resource
unirest.get('http://httpbin.org/get')
  .query({'foo': 'bar'})
  .query({'stack': 'overflow'})
  .end(function(res) {
    if (res.error) {
      console.log('GET error', res.error)
    } else {
      console.log('GET response', res.body)
    }
  })

// POST a form with an attached file
unirest.post('http://httpbin.org/post')
  .field('foo', 'bar')
  .field('stack', 'overflow')
  .attach('myfile', 'examples.js')
  .end(function(res) {
    if (res.error) {
      console.log('POST error', res.error)
    } else {
      console.log('POST response', res.body)
    }
  })

Puedes saltar directamente a los documentos del Nodo aquí

Brian Beckett
fuente
3

Mira triturar . Es un cliente HTTP de nodo creado y mantenido por spire.io que maneja redirecciones, sesiones y respuestas JSON. Es ideal para interactuar con las API de descanso. Vea esta publicación de blog para más detalles.

Jonathan McIntire
fuente
3

Echa un vistazo a httpreq : es una biblioteca de nodos que creé porque estaba frustrado porque no había un módulo http GET o POST simple ;-)

Sam
fuente
0

Si solo necesita realizar solicitudes de obtención simples y no necesita soporte para ningún otro método HTTP, eche un vistazo a: simple-get :

var get = require('simple-get');

get('http://example.com', function (err, res) {
  if (err) throw err;
  console.log(res.statusCode); // 200
  res.pipe(process.stdout); // `res` is a stream
});
benjiman
fuente
0

Use reqclient : no está diseñado para fines de secuencias de comandos como requesto muchas otras bibliotecas. Reqclient permite en el constructor especificar muchas configuraciones útiles cuando necesita reutilizar la misma configuración una y otra vez: URL base, encabezados, opciones de autenticación, opciones de registro, almacenamiento en caché, etc. También tiene características útiles como consulta y análisis de URL, codificación automática de consultas y Análisis JSON, etc.

La mejor manera de usar la biblioteca es crear un módulo para exportar el objeto que apunta a la API y las configuraciones necesarias para conectarse con:

Módulo client.js:

let RequestClient = require("reqclient").RequestClient

let client = new RequestClient({
  baseUrl: "https://myapp.com/api/v1",
  cache: true,
  auth: {user: "admin", pass: "secret"}
})

module.exports = client

Y en los controladores donde necesita consumir el uso de API de esta manera:

let client = require('client')
//let router = ...

router.get('/dashboard', (req, res) => {
  // Simple GET with Promise handling to https://myapp.com/api/v1/reports/clients
  client.get("reports/clients")
    .then(response => {
       console.log("Report for client", response.userId)  // REST responses are parsed as JSON objects
       res.render('clients/dashboard', {title: 'Customer Report', report: response})
    })
    .catch(err => {
      console.error("Ups!", err)
      res.status(400).render('error', {error: err})
    })
})

router.get('/orders', (req, res, next) => {
  // GET with query (https://myapp.com/api/v1/orders?state=open&limit=10)
  client.get({"uri": "orders", "query": {"state": "open", "limit": 10}})
    .then(orders => {
      res.render('clients/orders', {title: 'Customer Orders', orders: orders})
    })
    .catch(err => someErrorHandler(req, res, next))
})

router.delete('/orders', (req, res, next) => {
  // DELETE with params (https://myapp.com/api/v1/orders/1234/A987)
  client.delete({
    "uri": "orders/{client}/{id}",
    "params": {"client": "A987", "id": 1234}
  })
  .then(resp => res.status(204))
  .catch(err => someErrorHandler(req, res, next))
})

reqclientadmite muchas características, pero tiene algunas que no son compatibles con otras bibliotecas: integración OAuth2 e integración de registrador con sintaxis cURL , y siempre devuelve objetos Promise nativos.

Mariano Ruiz
fuente
0

Si alguna vez necesita enviar una GETsolicitud a un IPasí como a Domain(Otras respuestas no mencionaron que puede especificar una portvariable), puede hacer uso de esta función:

function getCode(host, port, path, queryString) {
    console.log("(" + host + ":" + port + path + ")" + "Running httpHelper.getCode()")

    // Construct url and query string
    const requestUrl = url.parse(url.format({
        protocol: 'http',
        hostname: host,
        pathname: path,
        port: port,
        query: queryString
    }));

    console.log("(" + host + path + ")" + "Sending GET request")
    // Send request
    console.log(url.format(requestUrl))
    http.get(url.format(requestUrl), (resp) => {
        let data = '';

        // A chunk of data has been received.
        resp.on('data', (chunk) => {
            console.log("GET chunk: " + chunk);
            data += chunk;
        });

        // The whole response has been received. Print out the result.
        resp.on('end', () => {
            console.log("GET end of response: " + data);
        });

    }).on("error", (err) => {
        console.log("GET Error: " + err);
    });
}

No se pierda requerir módulos en la parte superior de su archivo:

http = require("http");
url = require('url')

También tenga en cuenta que puede usar el httpsmódulo para comunicarse a través de una red segura. entonces estas dos líneas cambiarían:

https = require("https");
...
https.get(url.format(requestUrl), (resp) => { ......
AmiNadimi
fuente
-1
## you can use request module and promise in express to make any request ##
const promise                       = require('promise');
const requestModule                 = require('request');

const curlRequest =(requestOption) =>{
    return new Promise((resolve, reject)=> {
        requestModule(requestOption, (error, response, body) => {
            try {
                if (error) {
                    throw error;
                }
                if (body) {

                    try {
                        body = (body) ? JSON.parse(body) : body;
                        resolve(body);
                    }catch(error){
                        resolve(body);
                    }

                } else {

                    throw new Error('something wrong');
                }
            } catch (error) {

                reject(error);
            }
        })
    })
};

const option = {
    url : uri,
    method : "GET",
    headers : {

    }
};


curlRequest(option).then((data)=>{
}).catch((err)=>{
})
izhar ahmad
fuente
(Como sucede, no resolverá el problema. Este código escuchará una solicitud, pero la pregunta es cómo enviar una solicitud )
Quentin
1
está arreglado, puedes probarlo. @Quentin
izhar ahmad