记录干杯

​( ゜- ゜)つロ 干杯 ~
开往

使用 Node.js 反向代理

需求

根据客户端请求路径的不同,转发请求到一个服务器内的不同端口,实现不同功能。例如接口 api.lifeni.life

技术

使用到的 npm 模块:

http-proxy-middleware 是用于处理代理的中间件,Github 链接:chimurai/http-proxy-middleware: The one-liner node.js http-proxy middleware for connect, express and browser-sync,里面有详细的文档。

过程

1. 安装必要的模块

npm i express
npm i http-proxy-middleware

2. 主要代码

新建 npm 项目时的入口文件是 app.js。在文件中加入下面的代码,代码来自官方示例,有翻译和改动。

// 添加依赖
const express = require('express');
const app = express();
const { createProxyMiddleware } = require('http-proxy-middleware');

// 官方实例的翻译,有改动

// 代理中间件选项
const options = {
  target: 'http://localhost:3001', // 目标地址

  // 把目标主机获取到的 Host 替换成目标地址
  // 当为 true 时,目标主机获取到的 Host 端口为 3001,反之为3000
  changeOrigin: false,

  ws: true, // 是否代理 WebSockets
  pathRewrite: {
    '^/api/old-path': '/api/new-path', // 重写路径
    '^/api/remove/path': '/path', // 移除中间的路径
  },
  router: {
    // 当 request.headers.host == 'dev.localhost:3000' 时,
    // 把目标地址 'http://www.example.org' 转换成 'http://localhost:8000'
    'dev.localhost:3000': 'http://localhost:8000',
  },
};

// 创建代理 (without context)
const exampleProxy = createProxyMiddleware(options);

// 挂载 `exampleProxy` 到服务器
app.use('/api', exampleProxy);

// ---------------
// 符合自己需求的写法
const optionProject = {
  target: 'http://localhost:3001',
  changeOrigin: false,
  ws: true,
  pathRewrite: {
    '^/project-name': '/',
  },
};
const myProxy = createProxyMiddleware(optionProject);
app.use('/project-name', myProxy);
app.listen(3000);

简单的注释已经在代码里写了,具体的效果可以看下面的测试。

3. 测试

测试同样使用 express 在本地起一个端口,这里用的是 3001。

下面的代码可以获取到 localhost:3001 的 Host 以及路径,帮助判断代理是否成功:

const express = require('express');
const app = express();

app.get('*', (req, res) => {
  console.log(req);
  res.end(req.headers.host + req.originalUrl);
});

app.listen(3001);

两个 Node 程序运行后进行测试:

高级的设置

官方给的示例已经够用了,但文档里还有一些其他的用法,以后可能会用到,所以在这里选一部分写,就当是翻译了。

内容匹配

下面是内容匹配的模式图,以 RFC 3986 path 为标准:

  foo://example.com:8042/over/there?name=ferret#nose
  \_/   \______________/\_________/ \_________/ \__/
   |           |            |            |        |
  协议    主机名和端口      路径        查询参数   锚点

代理选项

http-proxy-middleware optionshttp-proxy events 没有写,想看的可以去看原文。下面只翻译部分 http-proxy options(太简单的就不翻译了,没看懂的也不翻译了。。)。

下面这些选项来自底层的 http-proxy 库。

简写

简单的配置应该用简单的写法。使用简写的时候 contextoption.target(就是内容匹配和代理选项)会自动配置好,如果需要的话,还可以加上代理选项。

createProxyMiddleware('http://www.example.org:8000/api');
// createProxyMiddleware('/api', {target: 'http://www.example.org:8000'});

createProxyMiddleware('http://www.example.org:8000/api/books/*/**.json');
// createProxyMiddleware('/api/books/*/**.json', {target: 'http://www.example.org:8000'});

createProxyMiddleware('http://www.example.org:8000/api', {
  changeOrigin: true,
});
// createProxyMiddleware('/api', {target: 'http://www.example.org:8000', changeOrigin: true});

关于 app.use(path, proxy)

如果你用的是服务器上的 app.use path 去匹配请求,那么就创建下面这种没有中间件内容匹配的写法:

app.use(
  '/api',
  createProxyMiddleware({
    target: 'http://www.example.org',
    changeOrigin: true,
  })
);

app.use 的文档:

WebSocket

// 长 api
createProxyMiddleware('/', { target: 'http://echo.websocket.org', ws: true });

// 短
createProxyMiddleware('http://echo.websocket.org', { ws: true });

// 更短
createProxyMiddleware('ws://echo.websocket.org');

此处还有拓展的用法,可以去看文档,这里没翻译。

问题解决

  1. 如何在访问根路径时返回静态网页?

    假设静态网页的目录是 /pubic,在 app.js 中加入下面的代码即可:

    app.use(express.static('public'));

参考资料

  1. chimurai/http-proxy-middleware: The one-liner node.js http-proxy middleware for connect, express and browser-sync
  2. Express “Hello World” example
  3. express 设置静态文件目录 - Alyson.fu - 博客园
网站正在重新设计中,部分功能和内容还没完成。