HOWTO · Node.js
NodeJS 中的 HTTP 代理服务器
本教程演示如何在 NodeJS 中创建 http 代理服务器。
本页内容
代理会接收客户端请求,并将其转发给另一台服务器。本指南将创建一个 Express 路由,把 /user_info 下的请求转发到上游服务,然后演示一个检查请求标头是否存在的中间件。该演示用于说明请求流程,并非生产环境可用的身份验证方案。
在 Node.js 中创建 HTTP 代理
安装 Node.js 和 npm,然后运行 npm init -y 创建项目。运行 npm install express http-proxy-middleware 安装 Express 和代理中间件包。该包会导出下文使用的 createProxyMiddleware 工厂函数。官方文档介绍了这个工厂函数,以及 target、origin 和路径重写选项。生成的 package manifest 会因 npm 版本而异,因此请使用安装命令,而不要照抄固定的 manifest。
配置代理路由并重写路径
创建 index.js,并使用 CommonJS 的 require() 导入依赖项。授权中间件挂载在 /user_info 上;代理中间件则由一个未挂载的 Express 处理函数调用,调用前会检查请求路径是否以 /user_info/ 开头。这样,代理就能接收到完整路径。pathRewrite 规则会移除这个前缀:上游收到的路径会从 /user_info/data/v1/user/example 变为 /data/v1/user/example。将 target 设为你控制的上游源站;如果上游要求使用自己的主机名,可设置 changeOrigin。
以下代码行按顺序拼接后即为 index.js。标头中间件先于代理运行,服务器监听端口 8080:
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const app = express();
app.use('/user_info', (req, res, next) => {
if (!req.headers.authorization) return res.sendStatus(403);
next();
});
const proxy = createProxyMiddleware({
target: 'https://api.example.com',
changeOrigin: true,
pathRewrite: { '^/user_info': '' }
});
app.use((req, res, next) => {
if (!req.path.startsWith('/user_info/')) return next();
proxy(req, res, next);
});
app.listen(8080, () => console.log('Proxy listening on port 8080'));
若要在不依赖实时上游服务的情况下演示路径和标头的处理逻辑,可以运行下面这个仅使用内置功能的示例:
本节中的代码以及显示的标签或输出仍为英文。
const rewrite = path => path.replace(/^\/user_info/, '');
const authorizationGate = headers => Boolean(headers.authorization);
const incomingPath = '/user_info/data/v1/user/example';
console.log(`Upstream path: ${rewrite(incomingPath)}`);
console.log(`Request without Authorization: ${authorizationGate({}) ? 'allowed' : '403 Forbidden'}`);
console.log(`Request with Authorization: ${authorizationGate({ authorization: 'present' }) ? 'allowed' : '403 Forbidden'}`);
Upstream path: /data/v1/user/example
Request without Authorization: 403 Forbidden
Request with Authorization: allowed
这个小示例模拟了预期的处理逻辑。代码块中的标签和输出保留为英文。Express 应用本身依赖已安装的两个软件包和一个上游服务。
运行并测试代理
将 https://api.example.com 替换为能够接收重写后路径的上游源站,然后运行 node index.js 启动应用。使用 curl http://localhost:8080/user_info/data/v1/user/example 发送请求。实际响应取决于上游服务,因此请检查响应状态和正文,不要预期会得到固定结果。如果收到未找到响应,可能是因为上游没有提供 /data/v1/user/example;请确认上游所需的路径。
添加 Authorization 中间件
第一个 /user_info 中间件只检查 Authorization 是否存在;如果存在,就调用 next(),将请求交给代理中间件继续处理。Express 按照中间件的注册顺序执行,因此这项检查必须放在前面。任何非空标头都会通过;代码不会验证身份、凭据或权限。应使用真正的身份验证系统处理这些事项,并避免记录机密值。
测试带有和不带有 Authorization 的请求
启动服务器,然后尝试运行 curl -i http://localhost:8080/user_info/data/v1/user/example;如果请求不带标头,演示中间件会在转发前返回 HTTP 403。接着发送带有测试标头的请求,例如 curl -i -H 'Authorization: test-value' http://localhost:8080/user_info/data/v1/user/example。该请求会继续转发到上游,响应取决于上游的路由和访问规则。不要在 Shell 历史记录或示例中放入真实凭据。如果不带标头的请求仍到达上游,请确认 /user_info 的标头检查中间件注册在调用代理之前。代理是在另一个未挂载的处理函数中调用的,该函数会检查 /user_info/ 前缀;它本身并未挂载在 /user_info 上。