Node Reverse Proxy

这几天做GazeLabel的时候,遇到了CORS的跨域问题,主要情况是api-faceplusplus作为一个公开使用的API,居然不返回ACAO头,这样preflight就凉了...所以,面对这种素质较差的API提供商,我们选择用反代的形式解决这个问题。

由于是Nuxt的项目,所以本文以Node为主。当然为了更好的性能,Nginx也是可以反代的,还有一些类似与HAProxy的代理也可以使用。

首先,node内建的request包肯定是首选。因为它不仅不需要额外的依赖,更好的是它可以无损把接收到的信息pipe回去。但是,express项目中,没有自带body-parser,所以如果是需要req.body的处理,建议先安装body-parser再考虑处理后续的请求。


app.post('/api/method', (req, res) => {
  req.pipe(request.post(someUrl, { json: true, body: req.body }), { end: false }).pipe(res);
}

这样,通过直接把请求pipe到request里面,然后再把结果pipe出来,效果非常好。

有个坑就是如果不确定请求的来源的METHOD,似乎不是很方便去把对应的请求方式pipe到request的特定方式下,只能通过获取req.method或者req.url去判断并在request的option对象里面带上method: 'GET'

另外一种方式是通过一个叫做node-http-proxy的包,这个包可以很方便的代理所有某url下的请求。


const express = require('express');
const vhost = require('vhost');
const compression = require('compression');
const httpProxy = require('http-proxy');
const history = require('connect-history-api-fallback');
const app = express();
app.use(compression());
app.all('/api/*', (req, res) => {
  console.log(`reverse proxy REDIRECTED ${req.url} to port 5000`);
  try {
    apiProxy.web(req, res, { target: 'http://localhost:5000' });
  } catch (e) {
    console.log('proxy failed...Ignoring and continue');
  }
});

还有一种方式是CORS-anywhere插件,但是这个插件似乎不太好控制访问的连接,感觉带来了很多不安全性,不是非常推荐。但是这个插件可以让某个url指向任意地址并带上CORS头部,感觉还是很炫酷的。似乎POST和GET都可以。

最后,如果是axios的终极粉丝,也可以使用axios返回代理的结果,其实axios的API还是非常美好的,但是就是不支持直接pipe express的req请求,用起来就没有request那么方便了。

最后说一点题外话,body-parser这个包如果在请求体积太大的时候会抛出Entity too large的错误,解决方案是在参数里面带上limit: "50mb"放宽类似的限制,就可以了。