使用express.js代理

use*_*114 148 proxy reverse-proxy node.js express

为了避免同域AJAX问题,我希望我的node.js Web服务器将所有请求从URL转发/api/BLABLA到另一个服务器,例如other_domain.com:3000/BLABLA,并且透明地向用户返回该远程服务器返回的相同内容.

所有其他URL(旁边/api/*)将直接提供,不代理.

如何使用node.js + express.js实现此目的?你能给出一个简单的代码示例吗?

(Web服务器和远程3000服务器都在我的控制之下,都运行带有express.js的node.js)


到目前为止,我发现了这个https://github.com/nodejitsu/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
    });
});
Run Code Online (Sandbox Code Playgroud)

但没有任何东西返回原始的Web服务器(或最终用户),所以没有运气.

tri*_*man 204

我做了类似的事情,但我使用了请求:

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);
});
Run Code Online (Sandbox Code Playgroud)

我希望这会有所帮助,花了一段时间才意识到我能做到这一点:)

  • 更简单,如果你也管道请求:http://stackoverflow.com/questions/7559862/proxy-with-nodejs-and-express/20539239#20539239 (15认同)
  • 谢谢,比使用Node.js的HTTP请求简单得多 (5认同)

Sel*_*ish 64

我找到了一个更简洁,更直接的解决方案,它可以无缝地工作,并且通过身份验证,使用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', {
    forwardPath: req => url.parse(req.baseUrl).path
});
Run Code Online (Sandbox Code Playgroud)

然后简单地说:

app.use('/api/*', apiProxy);
Run Code Online (Sandbox Code Playgroud)

注意:正如@MaxPRafferty所提到的,用来req.originalUrl代替baseUrl保存查询字符串:

    forwardPath: req => url.parse(req.baseUrl).path
Run Code Online (Sandbox Code Playgroud)

更新:如安德鲁所述(谢谢!),有一个现成的解决方案使用相同的原则:

npm i --save http-proxy-middleware
Run Code Online (Sandbox Code Playgroud)

然后:

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

文档:Github上的http-proxy-middleware

我知道我参加这个派对已经很晚了,但我希望这对某人有所帮助.

  • 我还喜欢使用 req.originalUrl 代替 baseUrl 来保留查询字符串,但这可能并不总是所需的行为。 (4认同)
  • 这是最好的解决方案.我正在使用http-proxy-middleware,但它的概念相同.当有很好的代理解决方案时,不要转动自己的代理解决方案. (4认同)
  • req.url没有完整的url,所以更新了使用req.baseUrl而不是req.url的答案 (3认同)

Hen*_*nar 45

扩展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);
});
Run Code Online (Sandbox Code Playgroud)

  • @Protron for PUT请求只使用类似`if(req.method ==='PUT'){r = request.put({uri:url,json:req.body}); }` (5认同)
  • 无法使其与 PUT 一起使用。但对于 GET 和 POST 非常有用。谢谢你!! (2认同)

mek*_*all 42

您希望用于http.request创建与远程API类似的请求并返回其响应.

像这样的东西:

var http = require('http');

/* your app config here */

app.post('/api/BLABLA', function(req, res) {

  var 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: req.headers
  };

  var creq = http.request(options, function(cres) {

    // set encoding
    cres.setEncoding('utf8');

    // wait for data
    cres.on('data', function(chunk){
      res.write(chunk);
    });

    cres.on('close', function(){
      // closed, let's end client request as well 
      res.writeHead(cres.statusCode);
      res.end();
    });

    cres.on('end', function(){
      // finished, let's finish client request as well 
      res.writeHead(cres.statusCode);
      res.end();
    });

  }).on('error', function(e) {
    // we got an error, return 500 error to client and log error
    console.log(e.message);
    res.writeHead(500);
    res.end();
  });

  creq.end();

});
Run Code Online (Sandbox Code Playgroud)

注意:我没有真正尝试过上述内容,所以它可能包含解析错误,希望这会给你一个关于如何让它工作的提示.

  • @ user124114-请输入您使用过的完整解决方案 (3认同)
  • 是的,需要进行一些修改,但是我比引入一个额外的新“代理”模块依赖项更好。有点冗长,但至少我确切地知道发生了什么。干杯。 (2认同)

Ant*_*met 20

我使用以下设置将所有内容定向/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);
Run Code Online (Sandbox Code Playgroud)

  • 这是唯一一个也处理网络套接字的。 (4认同)

小智 9

首先安装express和http-proxy-middleware

npm install express http-proxy-middleware --save
Run Code Online (Sandbox Code Playgroud)

然后在你的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');
});
Run Code Online (Sandbox Code Playgroud)

在此示例中,我们在端口3000上提供站点服务,但是当请求以/ api结尾时,我们将其重定向到localhost:8080.

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


cod*_*ion 6

好的,这是使用require('request')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
Run Code Online (Sandbox Code Playgroud)

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);
});
Run Code Online (Sandbox Code Playgroud)

  • 您可以先清理(例如,如果方法不在已批准方法列表中,则调用默认值的if语句),而不是一个案例语句,除了使用不同的请求函数之外都会执行相同的操作),然后只做r =请求[方法](/*其余的*/); (2认同)