एक्सप्रेस के साथ प्रॉक्सी। Js


168

समान-डोमेन AJAX के मुद्दों से बचने के लिए, मैं चाहता हूं कि मेरा नोड। Js वेब सर्वर URL /api/BLABLAसे किसी अन्य सर्वर के लिए सभी अनुरोधों को अग्रेषित करें, उदाहरण के लिए other_domain.com:3000/BLABLA, और उपयोगकर्ता को उसी चीज़ पर वापस लौटाएं जो यह रिमोट सर्वर पारदर्शी रूप से लौटा है।

अन्य सभी URL (बगल में /api/*) सीधे परोसे जाने हैं, कोई भी आसन्न नहीं है।

मैं इसे नोड.जेएस + एक्सप्रेस.जेएस के साथ कैसे प्राप्त कर सकता हूं? क्या आप एक सरल कोड उदाहरण दे सकते हैं?

(वेब सर्वर और रिमोट 3000सर्वर दोनों मेरे नियंत्रण में हैं। दोनों नोड के साथ चल रहे हैं। एक्सप्रेस के साथ जेएस)


अब तक मुझे यह https://github.com/http-party/node-http-proxy मिला है , लेकिन वहां के डॉक्यूमेंटेशन को पढ़ने से मुझे कोई समझदार नहीं लगा। मैं खत्म हो गया

var proxy = new httpProxy.RoutingProxy();
app.all("/api/*", function(req, res) {
    console.log("old request url " + req.url)
    req.url = '/' + req.url.split('/').slice(2).join('/'); // remove the '/api' part
    console.log("new request url " + req.url)
    proxy.proxyRequest(req, res, {
        host: "other_domain.com",
        port: 3000
    });
});

लेकिन मूल वेब सर्वर (या अंतिम उपयोगकर्ता) को कुछ भी नहीं लौटाया जाता है, इसलिए कोई भाग्य नहीं।


जिस तरह से आप मेरे लिए काम कर रहे हैं, बिना किसी संशोधन के
सॉले

1
हालांकि जवाब देने में थोड़ा बहुत देर हो गई, लेकिन इसी तरह के मुद्दे का सामना करना पड़ रहा था और बॉडी पार्सर को हटाकर इसे हल कर दिया गया, ताकि अनुरोध करने के बाद इसे आगे बढ़ाने से पहले शरीर को पार्स नहीं किया जा सके।
व्योवित

जवाबों:


52

आप http.requestदूरस्थ API के समान अनुरोध बनाने और उसकी प्रतिक्रिया वापस करने के लिए उपयोग करना चाहते हैं ।

कुछ इस तरह:

const http = require('http');
// or use import http from 'http';


/* your app config here */

app.post('/api/BLABLA', (oreq, ores) => {
  const options = {
    // host to forward to
    host: 'www.google.com',
    // port to forward to
    port: 80,
    // path to forward to
    path: '/api/BLABLA',
    // request method
    method: 'POST',
    // headers to send
    headers: oreq.headers,
  };

  const creq = http
    .request(options, pres => {
      // set encoding
      pres.setEncoding('utf8');

      // set http status code based on proxied response
      ores.writeHead(pres.statusCode);

      // wait for data
      pres.on('data', chunk => {
        ores.write(chunk);
      });

      pres.on('close', () => {
        // closed, let's end client request as well
        ores.end();
      });

      pres.on('end', () => {
        // finished, let's finish client request as well
        ores.end();
      });
    })
    .on('error', e => {
      // we got an error
      console.log(e.message);
      try {
        // attempt to set error message and http status
        ores.writeHead(500);
        ores.write(e.message);
      } catch (e) {
        // ignore
      }
      ores.end();
    });

  creq.end();
});

सूचना: मैंने वास्तव में ऊपर की कोशिश नहीं की है, इसलिए इसमें पार्स त्रुटियां हो सकती हैं उम्मीद है कि यह आपको संकेत देगा कि इसे कैसे काम करना है।


5
हाँ, कुछ संशोधन आवश्यक थे, लेकिन मुझे यह अतिरिक्त नया "प्रॉक्सी" मॉड्यूल निर्भरता शुरू करने से बेहतर है। थोड़ी सी क्रिया, लेकिन कम से कम मुझे पता है कि वास्तव में क्या हो रहा है। चीयर्स।
user124114

ऐसा लगता है कि आपको डेटा लिखने से पहले Res.writeHead करना होगा, अन्यथा आपको त्रुटि मिलेगी (हेडर कैंट बॉडी के साथ लिखा जा सकता है)।
सेट

3
@ user124114 - कृपया पूर्ण समाधान जिसे आपने इस्तेमाल किया है
मिशाल त्सादोक

1
लगता है कि आपको इस तरह हेडर सेट करने में समस्या होगी। Cannot render headers after they are sent to the client
शैंड

1
मैंने es6 सिंटैक्स के उत्तर को अपडेट किया है और राइटहेड मुद्दे को तय किया है
mekwall

219

अनुरोध को फरवरी 2020 तक हटा दिया गया है, मैं नीचे दिए गए उत्तर को ऐतिहासिक कारणों के लिए छोड़ दूंगा, लेकिन कृपया इस मुद्दे में सूचीबद्ध एक विकल्प पर जाने पर विचार करें ।

पुरालेख

मैंने भी कुछ ऐसा ही किया लेकिन मैंने इसके बजाय अनुरोध का इस्तेमाल किया :

var request = require('request');
app.get('/', function(req,res) {
  //modify the url in any way you want
  var newurl = 'http://google.com/';
  request(newurl).pipe(res);
});

मुझे आशा है कि यह मदद करता है, मुझे यह महसूस करने में थोड़ा समय लगा कि मैं यह कर सकता हूं :)


5
धन्यवाद, Node.js के HTTP अनुरोध का उपयोग करने की तुलना में बहुत सरल है
एलेक्स Turpin

17
और भी सरल, यदि आप भी अनुरोध को स्वीकार करते हैं: stackoverflow.com/questions/7559862/…
Stephan Hoyer

1
अच्छा और साफ समाधान। मैंने इसे POST अनुरोध के साथ भी काम करने के लिए एक उत्तर पोस्ट किया है (अन्यथा यह आपके पोस्ट बॉडी को API के लिए अग्रेषित नहीं करता है)। यदि आप अपना उत्तर संपादित करते हैं तो मुझे मेरा निकालने में खुशी होगी।
हेनरिक पाइनार

सुधार त्रुटि से निपटने के लिए यह उत्तर भी देखें ।
तमलिन

जब भी मैं इसी तरह की रूटिंग (या ठीक उसी) करने की कोशिश करता हूं, तो मैं निम्नलिखित के साथ समाप्त होता हूं: stream.js: 94 थ्रो एर; // पाइप में अनहेल्दी स्ट्रीम एरर। ^ त्रुटि: getaddrinfo ENOTFOUND google.com पर ग़लती से अपवाद (dns.js: 44: 10) GetAddrInfoReqWrap.onlookup [oncomplete के रूप में] (dj .js: 94: 26) कोई विचार?
कीनाबेल

82

मुझे एक छोटा और बहुत सीधा समाधान मिला, जो मूल रूप से काम करता है, और प्रमाणीकरण के साथ, उपयोग करते हुए express-http-proxy:

const url = require('url');
const proxy = require('express-http-proxy');

// New hostname+path as specified by question:
const apiProxy = proxy('other_domain.com:3000/BLABLA', {
    proxyReqPathResolver: req => url.parse(req.baseUrl).path
});

और फिर बस:

app.use('/api/*', apiProxy);

नोट: जैसा कि @MaxPRafferty द्वारा बताया गया है, क्वेरिस्ट्रिंग को संरक्षित करने के req.originalUrlस्थान पर उपयोग करें baseUrl:

    forwardPath: req => url.parse(req.baseUrl).path

अपडेट: जैसा कि एंड्रयू द्वारा उल्लेख किया गया है (धन्यवाद!), एक ही सिद्धांत का उपयोग करके तैयार समाधान है:

npm i --save http-proxy-middleware

और तब:

const proxy = require('http-proxy-middleware')
var apiProxy = proxy('/api', {target: 'http://www.example.org/api'});
app.use(apiProxy)

प्रलेखन: http-प्रॉक्सी-मिडिलवेयर गिथब पर

मुझे पता है कि मुझे इस पार्टी में शामिल होने में देर हो रही है, लेकिन मुझे उम्मीद है कि इससे किसी को मदद मिलेगी।


3
Req.url में पूरा url नहीं है, इसलिए req.baseUrl के बजाय req.url का उपयोग करने का उत्तर अपडेट किया गया
कुमार

1
मैं भी querystrings को संरक्षित करने के लिए baseUrl के स्थान पर req.originalUrl का उपयोग करना पसंद करता हूं, लेकिन यह हमेशा वांछित व्यवहार नहीं हो सकता है।
मैक्सप्रैफर्टी

@MaxPRafferty - वैद टिप्पणी ध्यान देने योग्य। धन्यवाद।
स्वार्थी

4
यह सबसे अच्छा उपाय है। मैं http-प्रॉक्सी-मिडलवेयर का उपयोग कर रहा हूं, लेकिन यह एक ही अवधारणा है। जब वहाँ पहले से ही महान लोग हैं तो अपने स्वयं के प्रॉक्सी समाधान को स्पिन न करें।
एंड्रयू

1
@tannerburton धन्यवाद! मैंने जवाब अपडेट किया।
स्वार्थी

46

POST के साथ काम करने के लिए ट्राइगमैन के उत्तर (उसके लिए पूर्ण क्रेडिट) का विस्तार करने के लिए (PUT आदि के साथ भी काम कर सकते हैं):

app.use('/api', function(req, res) {
  var url = 'YOUR_API_BASE_URL'+ req.url;
  var r = null;
  if(req.method === 'POST') {
     r = request.post({uri: url, json: req.body});
  } else {
     r = request(url);
  }

  req.pipe(r).pipe(res);
});

1
यह PUT के साथ काम नहीं कर सका। लेकिन GET और POST के लिए बढ़िया काम करता है। धन्यवाद!!
मारियानो देशनज

5
@ PUT अनुरोधों के लिए Protron बस कुछ का उपयोग करें जैसेif(req.method === 'PUT'){ r = request.put({uri: url, json: req.body}); }
davnicwil

यदि आपको किसी PUT या POST अनुरोध के भाग के रूप में शीर्षलेखों से गुजरना है, तो सामग्री-लंबाई शीर्षलेख को हटाना सुनिश्चित करें ताकि अनुरोध इसकी गणना कर सके। अन्यथा, प्राप्त सर्वर डेटा को छोटा कर सकता है, जिससे त्रुटि होगी।
कार्लोस राइमर

@ हेनरिक पीनर, जब मैं लॉगिन पोस्ट अनुरोध करूंगा और web.com/api/login से web.com/
valik

22

मैंने /restअपने बैकएंड सर्वर (पोर्ट 8080 पर) पर सब कुछ निर्देशित करने के लिए और फ्रंटएंड सर्वर के सभी अन्य अनुरोधों (पोर्ट 3001 पर एक वेबपैक सर्वर) का उपयोग करने के लिए मैंने निम्नलिखित सेटअप का उपयोग किया । यह सभी HTTP- विधियों का समर्थन करता है, मेटा-जानकारी का कोई भी अनुरोध नहीं खोता है और वेबस्कैट का समर्थन करता है (जिसे मुझे गर्म पुनः लोड करने की आवश्यकता है)

var express  = require('express');
var app      = express();
var httpProxy = require('http-proxy');
var apiProxy = httpProxy.createProxyServer();
var backend = 'http://localhost:8080',
    frontend = 'http://localhost:3001';

app.all("/rest/*", function(req, res) {
  apiProxy.web(req, res, {target: backend});
});

app.all("/*", function(req, res) {
    apiProxy.web(req, res, {target: frontend});
});

var server = require('http').createServer(app);
server.on('upgrade', function (req, socket, head) {
  apiProxy.ws(req, socket, head, {target: frontend});
});
server.listen(3000);

1
यह केवल एक ही है जो वेब-सॉकेट्स से संबंधित है।
sec0ndHand

11

पहले स्थापित एक्सप्रेस और HTTP- प्रॉक्सी-मिडलवेयर

npm install express http-proxy-middleware --save

फिर अपने server.js में

const express = require('express');
const proxy = require('http-proxy-middleware');

const app = express();
app.use(express.static('client'));

// Add middleware for http proxying 
const apiProxy = proxy('/api', { target: 'http://localhost:8080' });
app.use('/api', apiProxy);

// Render your site
const renderIndex = (req, res) => {
  res.sendFile(path.resolve(__dirname, 'client/index.html'));
}
app.get('/*', renderIndex);

app.listen(3000, () => {
  console.log('Listening on: http://localhost:3000');
});

इस उदाहरण में हम पोर्ट 3000 पर साइट की सेवा करते हैं, लेकिन जब एक अनुरोध समाप्त होता है, तो हम इसे लोकलहोस्ट: 8080 पर पुनर्निर्देशित कर देते हैं।

http: // localhost: 3000 / एपीआई / लॉगिन रीडायरेक्ट http: // localhost: 8080 / एपीआई / लॉगिन


6

ठीक है, यहाँ एक तैयार-टू-कॉपी-पेस्ट जवाब है जिसमें ('अनुरोध') npm मॉड्यूल और एक पर्यावरण चर का उपयोग करके हार्डकोड किए गए प्रॉक्सी के बजाय):

coffeescript

app.use (req, res, next) ->                                                 
  r = false
  method = req.method.toLowerCase().replace(/delete/, 'del')
  switch method
    when 'get', 'post', 'del', 'put'
      r = request[method](
        uri: process.env.PROXY_URL + req.url
        json: req.body)
    else
      return res.send('invalid method')
  req.pipe(r).pipe res

जावास्क्रिप्ट:

app.use(function(req, res, next) {
  var method, r;
  method = req.method.toLowerCase().replace(/delete/,"del");
  switch (method) {
    case "get":
    case "post":
    case "del":
    case "put":
      r = request[method]({
        uri: process.env.PROXY_URL + req.url,
        json: req.body
      });
      break;
    default:
      return res.send("invalid method");
  }
  return req.pipe(r).pipe(res);
});

2
एक केस स्टेटमेंट के बजाय, जो सभी एक ही कार्य को छोड़कर एक अलग अनुरोध फ़ंक्शन का उपयोग करते हैं) आप पहले सैनिटाइज़ कर सकते हैं (उदाहरण के लिए एक स्टेटमेंट जो आपके डिफ़ॉल्ट को कॉल करता है यदि विधि अनुमोदित विधियों की सूची में नहीं है), और फिर बस करें आर = अनुरोध [विधि] (/ * बाकी * /);
पॉल

2

मुझे एक छोटा सा समाधान मिला जो ठीक वैसा ही है जैसा मैं चाहता हूं कि https://github.com/http-party/node-http-proxy

इंस्टॉल करने के बाद http-proxy

npm install http-proxy --save

अपने सर्वर / सूचकांक / app.js में नीचे की तरह इसका उपयोग करें

var proxyServer = require('http-route-proxy');
app.use('/api/BLABLA/', proxyServer.connect({
  to: 'other_domain.com:3000/BLABLA',
  https: true,
  route: ['/']
}));

मैंने वास्तव में इस मुद्दे से बचने के लिए हर जगह देख कर दिन बिताए हैं, बहुत सारे समाधानों की कोशिश की है और उनमें से किसी ने भी काम नहीं किया है।

आशा है कि यह किसी और की मदद करने जा रहा है :)


0

मेरे पास एक एक्सप्रेस नमूना नहीं है, लेकिन एक सादे http-proxyपैकेज के साथ । मेरे ब्लॉग के लिए उपयोग किए जाने वाले प्रॉक्सी का एक बहुत ही स्ट्रिप डाउन संस्करण।

संक्षेप में, सभी नोडज http प्रॉक्सी पैकेज http प्रोटोकॉल स्तर पर काम करते हैं, tcp (सॉकेट) स्तर पर नहीं। यह एक्सप्रेस और सभी एक्सप्रेस मिडलवेयर के लिए भी सही है। उनमें से कोई भी पारदर्शी प्रॉक्सी नहीं कर सकता है, न ही NAT, जिसका अर्थ है आने वाले ट्रैफ़िक स्रोत IP को पैकेट में वेब सर्वर को बैकेंड भेजने के लिए रखना।

हालाँकि, वेब सर्वर HTTP x-अग्रेषित हेडर से मूल आईपी पिक कर सकता है और लॉग में जोड़ सकता है।

xfwd: trueमें proxyOptionके लिए एक्स-आगे हैडर सुविधा को सक्षम http-proxy

const url = require('url');
const proxy = require('http-proxy');

proxyConfig = {
    httpPort: 8888,
    proxyOptions: {
        target: {
            host: 'example.com',
            port: 80
        },
        xfwd: true // <--- This is what you are looking for.
    }
};

function startProxy() {

    proxy
        .createServer(proxyConfig.proxyOptions)
        .listen(proxyConfig.httpPort, '0.0.0.0');

}

startProxy();

एक्स-फॉरवर्ड हेडर का संदर्भ: https://en.wikipedia.org/wiki/X-Forwarded-For

मेरे प्रॉक्सी का पूर्ण संस्करण: https://github.com/J-Siu/ghost-https-nodejs-proxy

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.