Saya ingin membuka halaman di node dan memproses konten dalam aplikasi saya. Sesuatu seperti ini sepertinya bekerja dengan baik:
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
});
Namun ini tidak berhasil, jika halaman mengembalikan pengalihan 301/302. Bagaimana saya melakukannya dengan cara yang dapat digunakan kembali jika ada beberapa pengalihan? Apakah ada modul pembungkus di atas http agar lebih mudah menangani pemrosesan tanggapan http dari aplikasi node?
node.js
http-redirect
Zach
sumber
sumber
http.request
API cukup sederhana.http
modul bawaan tidak mengikuti pengalihan, oleh karena itu ini bukan bagian darihttp
modul bawaan.request
sudah tidak digunakan lagi.Jika yang ingin Anda lakukan hanyalah mengikuti pengalihan tetapi masih ingin menggunakan modul HTTP dan HTTPS bawaan, saya sarankan Anda menggunakan https://github.com/follow-redirects/follow-redirects .
Yang perlu Anda lakukan hanyalah mengganti:
var http = require('http');
dengan
var http = require('follow-redirects').http;
... dan semua permintaan Anda akan otomatis mengikuti pengalihan.
Dengan TypeScript Anda juga dapat menginstal jenisnya
dan kemudian gunakan
import { http, https } from 'follow-redirects';
Pengungkapan: Saya menulis modul ini.
sumber
request
yang akan menambahkan 20+ dependensi baru ke modul Anda untuk tugas sederhana seperti itu. Terima kasih telah menjaga modul npm tetap ringan, Oliver! :)Memperbarui:
Sekarang Anda dapat mengikuti semua pengalihan dengan
var request = require('request');
menggunakanfollowAllRedirects
param.request({ followAllRedirects: true, url: url }, function (error, response, body) { if (!error) { console.log(response); } });
sumber
http
tetapi kemudian Anda menggunakan fungsi yang disebutrequest
request
sudah tidak digunakan lagiBuat permintaan lain berdasarkan
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);
sumber
response.headers.location
Berikut adalah fungsi yang saya gunakan untuk mengambil url yang memiliki pengalihan:
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); } }); }
ini berfungsi sama seperti http.get tetapi ikuti pengalihan.
sumber
Dalam kasus Permintaan PUT atau POST. jika Anda menerima statusCode 405 atau metode tidak diperbolehkan. Coba implementasi ini dengan pustaka " request ", dan tambahkan properti yang disebutkan.
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); } }); }
sumber
Berikut adalah pendekatan saya untuk mengunduh JSON dengan node biasa, tidak diperlukan paket.
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));
sumber
Jika Anda memiliki
https
server, ubah url Anda untuk menggunakanhttps://
protokol.Saya mengalami masalah serupa dengan yang satu ini. Url saya memiliki
http://
protokol dan saya ingin membuatPOST
permintaan, tetapi server ingin mengalihkannya kehttps
. Apa yang terjadi adalah, ternyata node http perilaku mengirimkan permintaan redirect (berikutnya) dalamGET
metode yang tidak terjadi.Apa yang saya lakukan adalah mengubah url saya ke
https://
protokol dan berhasil.sumber
Mungkin ada sedikit postingan necromancing di sini, tapi ...
berikut adalah fungsi yang mengikuti hingga 10 pengalihan, dan mendeteksi pengalihan pengalihan tak terbatas. juga mengurai hasil menjadi JSON
Catatan - menggunakan pembantu panggilan balik (ditampilkan di akhir posting ini)
(TLDR; demo yang berfungsi penuh dalam konteks di sini atau versi remix di sini )
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); }
Catatan - menggunakan pembantu panggilan balik (ditampilkan di bawah)
Anda dapat menempelkannya ke konsol node dan seharusnya berjalan sebagaimana mestinya.
(atau untuk demo kerja penuh dalam konteks lihat di sini )
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));
sumber