Quiero abrir una página en el nodo y procesar el contenido en mi aplicación. Algo como esto parece funcionar bien:
var opts = {host: host, path:pathname, port: 80};
http.get(opts, function(res) {
var page = '';
res.on('data', function (chunk) {
page += chunk;
});
res.on('end', function() {
// process page
});
Sin embargo, esto no funciona si la página devuelve un redireccionamiento 301/302. ¿Cómo haría eso de una manera reutilizable en caso de que haya múltiples redireccionamientos? ¿Hay un módulo contenedor encima de http para manejar más fácilmente el procesamiento de respuestas http desde una aplicación de nodo?
node.js
http-redirect
Zach
fuente
fuente
http.request
API y es bastante simple.http
módulo incorporado no sigue las redirecciones, por lo tanto, esto no es parte delhttp
módulo incorporado .request
ha quedado obsoleto.Si todo lo que desea hacer es seguir las redirecciones, pero aún desea utilizar los módulos integrados HTTP y HTTPS, le sugiero que utilice https://github.com/follow-redirects/follow-redirects .
Todo lo que necesita hacer es reemplazar:
var http = require('http');
con
var http = require('follow-redirects').http;
... y todas sus solicitudes seguirán automáticamente las redirecciones.
Con TypeScript también puede instalar los tipos
y luego usa
import { http, https } from 'follow-redirects';
Divulgación: escribí este módulo.
fuente
request
que agregaría más de 20 nuevas dependencias a su módulo para una tarea tan simple. ¡Gracias por mantener los módulos npm livianos, Oliver! :)Actualizar:
Ahora puede seguir todas las redirecciones con el
var request = require('request');
uso defollowAllRedirects
param.request({ followAllRedirects: true, url: url }, function (error, response, body) { if (!error) { console.log(response); } });
fuente
http
pero luego usa una función llamadarequest
request
ha quedado obsoletoHaga otra solicitud basada en
response.headers.location
:const request = function(url) { lib.get(url, (response) => { var body = []; if (response.statusCode == 302) { body = []; request(response.headers.location); } else { response.on("data", /*...*/); response.on("end", /*...*/); }; } ).on("error", /*...*/); }; request(url);
fuente
response.headers.location
Aquí está la función que uso para buscar la URL que tiene redireccionamiento:
const http = require('http'); const url = require('url'); function get({path, host}, callback) { http.get({ path, host }, function(response) { if (response.headers.location) { var loc = response.headers.location; if (loc.match(/^http/)) { loc = new Url(loc); host = loc.host; path = loc.path; } else { path = loc; } get({host, path}, callback); } else { callback(response); } }); }
funciona igual que http.get pero sigue la redirección.
fuente
En caso de solicitud PUT o POST. si recibe statusCode 405 o método no permitido. Pruebe esta implementación con la biblioteca " solicitud " y agregue las propiedades mencionadas.
followAllRedirects: true,
followOriginalHttpMethod: true
const options = { headers: { Authorization: TOKEN, 'Content-Type': 'application/json', 'Accept': 'application/json' }, url: `https://${url}`, json: true, body: payload, followAllRedirects: true, followOriginalHttpMethod: true } console.log('DEBUG: API call', JSON.stringify(options)); request(options, function (error, response, body) { if (!error) { console.log(response); } }); }
fuente
Aquí está mi enfoque para descargar JSON con un nodo simple, no se requieren paquetes.
import https from "https"; function get(url, resolve, reject) { https.get(url, (res) => { if(res.statusCode === 301 || res.statusCode === 302) { return get(res.headers.location, resolve, reject) } let body = []; res.on("data", (chunk) => { body.push(chunk); }); res.on("end", () => { try { // remove JSON.parse(...) for plain data resolve(JSON.parse(Buffer.concat(body).toString())); } catch (err) { reject(err); } }); }); } async function getData(url) { return new Promise((resolve, reject) => get(url, resolve, reject)); } // call getData("some-url-with-redirect").then((r) => console.log(r));
fuente
Si tiene un
https
servidor, cambie su URL para usar elhttps://
protocolo.Me metí en un problema similar con este. Mi URL tiene
http://
protocolo y quiero hacer unaPOST
solicitud, pero el servidor quiere redirigirla ahttps
. Lo que sucede es que, resulta que el comportamiento http del nodo envía la solicitud de redireccionamiento (siguiente) enGET
método, lo cual no es el caso.Lo que hice fue cambiar mi URL a
https://
protocolo y funciona.fuente
Posiblemente una publicación de nigromante aquí, pero ...
aquí hay una función que sigue hasta 10 redireccionamientos y detecta bucles de redireccionamiento infinitos. también analiza el resultado en JSON
Nota: utiliza un asistente de devolución de llamada (que se muestra al final de esta publicación)
(TLDR; demostración funcional completa en contexto aquí o versión remezclada aquí )
function getJSON(url,cb){ var callback=errBack(cb); //var callback=errBack(cb,undefined,false);//replace previous line with this to turn off logging if (typeof url!=='string') { return callback.error("getJSON:expecting url as string"); } if (typeof cb!=='function') { return callback.error("getJSON:expecting cb as function"); } var redirs = [url], fetch = function(u){ callback.info("hitting:"+u); https.get(u, function(res){ var body = []; callback.info({statusCode:res.statusCode}); if ([301,302].indexOf(res.statusCode)>=0) { if (redirs.length>10) { return callback.error("excessive 301/302 redirects detected"); } else { if (redirs.indexOf(res.headers.location)<0) { redirs.push(res.headers.location); return fetch(res.headers.location); } else { return callback.error("301/302 redirect loop detected"); } } } else { res.on('data', function(chunk){ body.push(chunk); callback.info({onData:{chunkSize:chunk.length,chunks:body.length}}); }); res.on('end', function(){ try { // convert to a single buffer var json = Buffer.concat(body); console.info({onEnd:{chunks:body.length,bodyLength:body.length}}); // parse the buffer as json return callback.result(JSON.parse(json),json); } catch (err) { console.error("exception in getJSON.fetch:",err.message||err); if (json.length>32) { console.error("json==>|"+json.toString('utf-8').substr(0,32)+"|<=== ... (+"+(json.length-32)+" more bytes of json)"); } else { console.error("json==>|"+json.toString('utf-8')+"|<=== json"); } return callback.error(err,undefined,json); } }); } }); }; fetch(url); }
Nota: utiliza un asistente de devolución de llamada (que se muestra a continuación)
puede pegarlo en la consola del nodo y debería ejecutarse como está.
(o para una demostración de trabajo completa en contexto, consulte aquí )
var fs = require('fs'), https = require('https'); function errBack (cb,THIS,logger) { var self, EB=function(fn,r,e){ if (logger===false) { fn.log=fn.info=fn.warn=fn.errlog=function(){}; } else { fn.log = logger?logger.log : console.log.bind(console); fn.info = logger?logger.info : console.info.bind(console); fn.warn = logger?logger.warn : console.warn.bind(console); fn.errlog = logger?logger.error : console.error.bind(console); } fn.result=r; fn.error=e; return (self=fn); }; if (typeof cb==='function') { return EB( logger===false // optimization when not logging - don't log errors ? function(err){ if (err) { cb (err); return true; } return false; } : function(err){ if (err) { self.errlog(err); cb (err); return true; } return false; }, function () { return cb.apply (THIS,Array.prototype.concat.apply([undefined],arguments)); }, function (err) { return cb.apply (THIS,Array.prototype.concat.apply([typeof err==='string'?new Error(err):err],arguments)); } ); } else { return EB( function(err){ if (err) { if (typeof err ==='object' && err instanceof Error) { throw err; } else { throw new Error(err); } return true;//redundant due to throw, but anyway. } return false; }, logger===false ? self.log //optimization :resolves to noop when logger==false : function () { self.info("ignoring returned arguments:",Array.prototype.concat.apply([],arguments)); }, function (err) { throw typeof err==='string'?new Error(err):err; } ); } } function getJSON(url,cb){ var callback=errBack(cb); if (typeof url!=='string') { return callback.error("getJSON:expecting url as string"); } if (typeof cb!=='function') { return callback.error("getJSON:expecting cb as function"); } var redirs = [url], fetch = function(u){ callback.info("hitting:"+u); https.get(u, function(res){ var body = []; callback.info({statusCode:res.statusCode}); if ([301,302].indexOf(res.statusCode)>=0) { if (redirs.length>10) { return callback.error("excessive 302 redirects detected"); } else { if (redirs.indexOf(res.headers.location)<0) { redirs.push(res.headers.location); return fetch(res.headers.location); } else { return callback.error("302 redirect loop detected"); } } } else { res.on('data', function(chunk){ body.push(chunk); console.info({onData:{chunkSize:chunk.length,chunks:body.length}}); }); res.on('end', function(){ try { // convert to a single buffer var json = Buffer.concat(body); callback.info({onEnd:{chunks:body.length,bodyLength:body.length}}); // parse the buffer as json return callback.result(JSON.parse(json),json); } catch (err) { // read with "bypass refetch" option console.error("exception in getJSON.fetch:",err.message||err); if (json.length>32) { console.error("json==>|"+json.toString('utf-8').substr(0,32)+"|<=== ... (+"+(json.length-32)+" more bytes of json)"); } else { console.error("json==>|"+json.toString('utf-8')+"|<=== json"); } return callback.error(err,undefined,json); } }); } }); }; fetch(url); } var TLDs,TLDs_fallback = "com.org.tech.net.biz.info.code.ac.ad.ae.af.ag.ai.al.am.ao.aq.ar.as.at.au.aw.ax.az.ba.bb.bd.be.bf.bg.bh.bi.bj.bm.bn.bo.br.bs.bt.bv.bw.by.bz.ca.cc.cd.cf.cg.ch.ci.ck.cl.cm.cn.co.cr.cu.cv.cw.cx.cy.cz.de.dj.dk.dm.do.dz.ec.ee.eg.er.es.et.eu.fi.fj.fk.fm.fo.fr.ga.gb.gd.ge.gf.gg.gh.gi.gl.gm.gn.gp.gq.gr.gs.gt.gu.gw.gy.hk.hm.hn.hr.ht.hu.id.ie.il.im.in.io.iq.ir.is.it.je.jm.jo.jp.ke.kg.kh.ki.km.kn.kp.kr.kw.ky.kz.la.lb.lc.li.lk.lr.ls.lt.lu.lv.ly.ma.mc.md.me.mg.mh.mk.ml.mm.mn.mo.mp.mq.mr.ms.mt.mu.mv.mw.mx.my.mz.na.nc.ne.nf.ng.ni.nl.no.np.nr.nu.nz.om.pa.pe.pf.pg.ph.pk.pl.pm.pn.pr.ps.pt.pw.py.qa.re.ro.rs.ru.rw.sa.sb.sc.sd.se.sg.sh.si.sj.sk.sl.sm.sn.so.sr.st.su.sv.sx.sy.sz.tc.td.tf.tg.th.tj.tk.tl.tm.tn.to.tr.tt.tv.tw.tz.ua.ug.uk.us.uy.uz.va.vc.ve.vg.vi.vn.vu.wf.ws.ye.yt.za.zm.zw".split("."); var TLD_url = "https://gitcdn.xyz/repo/umpirsky/tld-list/master/data/en/tld.json"; var TLD_cache = "./tld.json"; var TLD_refresh_msec = 15 * 24 * 60 * 60 * 1000; var TLD_last_msec; var TLD_default_filter=function(dom){return dom.substr(0,3)!="xn-"}; function getTLDs(cb,filter_func){ if (typeof cb!=='function') return TLDs; var read,fetch, CB_WRAP=function(tlds){ return cb( filter_func===false ? cb(tlds) : tlds.filter( typeof filter_func==='function' ? filter_func : TLD_default_filter) ); }, check_mtime = function(mtime) { if (Date.now()-mtime > TLD_refresh_msec) { return fetch(); } if (TLDs) return CB_WRAP (TLDs); return read(); }; fetch = function(){ getJSON(TLD_url,function(err,data){ if (err) { console.log("exception in getTLDs.fetch:",err.message||err); return read(true); } else { TLDs=Object.keys(data); fs.writeFile(TLD_cache,JSON.stringify(TLDs),function(err){ if (err) { // ignore save error, we have the data CB_WRAP(TLDs); } else { // get mmtime for the file we just made fs.stat(TLD_cache,function(err,stats){ if (!err && stats) { TLD_last_msec = stats.mtimeMs; } CB_WRAP(TLDs); }); } }); } }); }; read=function(bypassFetch) { fs.readFile(TLD_cache,'utf-8',function(err,json){ try { if (err) { if (bypassFetch) { // after a http errror, we fallback to hardcoded basic list of tlds // if the disk file is not readable console.log("exception in getTLDs.read.bypassFetch:",err.messsage||err); throw err; } // if the disk read failed, get the data from the CDN server instead return fetch(); } TLDs=JSON.parse(json); if (bypassFetch) { // we need to update stats here as fetch called us directly // instead of being called by check_mtime return fs.stat(TLD_cache,function(err,stats){ if (err) return fetch(); TLD_last_msec =stats.mtimeMs; return CB_WRAP(TLDs); }); } } catch (e){ // after JSON error, if we aren't in an http fail situation, refetch from cdn server if (!bypassFetch) { return fetch(); } // after a http,disk,or json parse error, we fallback to hardcoded basic list of tlds console.log("exception in getTLDs.read:",err.messsage||err); TLDs=TLDs_fallback; } return CB_WRAP(TLDs); }); }; if (TLD_last_msec) { return check_mtime(TLD_last_msec); } else { fs.stat(TLD_cache,function(err,stats){ if (err) return fetch(); TLD_last_msec =stats.mtimeMs; return check_mtime(TLD_last_msec); }); } } getTLDs(console.log.bind(console));
fuente