簡體   English   中英

使用 express.js 代理

[英]Proxy with express.js

為了避免同域 AJAX 問題,我希望我的 node.js Web 服務器將來自 URL /api/BLABLA所有請求/api/BLABLA到另一台服務器,例如other_domain.com:3000/BLABLA ,並返回給用戶與此遠程服務器相同的內容服務器返回,透明。

所有其他 URL(除了/api/* )將直接提供,沒有代理。

我如何使用 node.js + express.js 實現這一點? 能舉個簡單的代碼例子嗎?

(web 服務器和遠程3000服務器都在我的控制之下,都運行 node.js 和 express.js)


到目前為止,我找到了這個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
    });
});

但是沒有任何東西返回到原始 Web 服務器(或最終用戶),所以沒有運氣。

自 2020 年 2 月起,請求已被棄用,出於歷史原因,我將在下面留下答案,但請考慮轉向本期中列出的替代方案。

檔案

我做了類似的事情,但我用request代替:

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);
});

我希望這會有所幫助,我花了一段時間才意識到我可以做到這一點:)

我找到了一個更短且非常簡單的解決方案,它可以無縫工作,並且還可以使用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

更新:正如 Andrew 所提到的(謝謝!),有一個使用相同原理的現成解決方案:

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)

文檔: Github 上的 http-proxy-middleware

我知道我加入這個聚會遲到了,但我希望這對某人有所幫助。

您想使用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();
});

注意:我還沒有真正嘗試過上面的方法,所以它可能包含解析錯誤,希望這會給你一個關於如何讓它工作的提示。

擴展trigoman的答案(他的全部學分)以使用 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);
});

我使用以下設置將/rest上的所有內容定向到我的后端服務器(端口 8080),並將所有其他請求定向到前端服務器(端口 3001 上的 webpack 服務器)。 它支持所有 HTTP 方法,不會丟失任何請求元信息並支持 websockets(我需要熱重載)

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);

首先安裝 express 和 http-proxy-middleware

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 上為站點提供服務,但是當請求以 /api 結束時,我們將其重定向到 localhost:8080。

http://localhost:3000/api/login重定向到http://localhost:8080/api/login

好的,這是使用 require('request') npm 模塊和環境變量 * 而不是硬編碼代理的准備復制粘貼答案:

咖啡腳本

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

javascript:

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);
});

我找到了一個更短的解決方案,它完全符合我的要求https://github.com/http-party/node-http-proxy

安裝http-proxy

npm install http-proxy --save

在你的 server/index/app.js 中像下面一樣使用它

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

我真的花了幾天時間到處尋找以避免這個問題,嘗試了很多解決方案,但沒有一個有效,只有這個。

希望它也能幫助別人:)

我認為你應該使用cors npm

const app = express();
const cors = require('cors');
var corsOptions = {
    origin: 'http://localhost:3000',
    optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204
}
app.use(cors(corsOptions));

https://www.npmjs.com/package/cors

我沒有快遞樣本,但有一個帶有普通http-proxy包的樣本。 我在博客中使用的代理的精簡版。

簡而言之,所有 nodejs http 代理包都在 http 協議級別工作,而不是 tcp(socket) 級別。 這也適用於 express 和所有 express 中間件。 它們都不能做透明代理,也不能做 NAT,這意味着將傳入流量源 IP 保留在發送到后端 Web 服務器的數據包中。

但是,Web 服務器可以從 http x 轉發的標頭中獲取原始 IP 並將其添加到日志中。

xfwd: trueproxyOption啟用X轉發頭功能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();

X-Forwarded 標頭參考: https : //en.wikipedia.org/wiki/X-Forwarded-For

我的代理的完整版本: https : //github.com/J-Siu/ghost-https-nodejs-proxy

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM