前言:现大部分项目都是前后端分离,与后端调试时需要使用其提供的服务接口,但是同时开发几个功能对应不同的接口人,这时候就需要频繁的切换接口IP,大部分项目切换IP时需要关闭项目重新启动,非常麻烦。使用node写一个代理就尤为重要,还能自定义返回内容以方便调试。
依赖安装
库介绍:
代理:http-proxy-middleware,使用比较广泛,配置也比较简单
请求拦截:express、body-parser
npm install express@4.18.2 http-proxy-middleware@2.0.6 body-parser@1.20.1 --save -dev
主要代码
const { createProxyMiddleware, responseInterceptor } = require('http-proxy-middleware');
const express = require('express');
const bodyParser = require('body-parser');
const http = require('http');
const https = require('https');
const url = require('url');
const app = express();
// 处理application/json内容格式的请求体
app.use(bodyParser.json());
// 处理application/x-www-form-urlencoded内容格式的请求体
app.use(bodyParser.urlencoded({ extended: true }));
// 选项
const options = {
xfwd: false,
selfHandleResponse: true, //是否修改响应内容
target: serverInfo.ip, // 目标服务器:代理ip+端口
changeOrigin: true, // 默认false,是否需要改变原始主机头为目标URL
ws: true, //代理socket
secure: false, //是否需要证书认证
router: function(req) { //动态代理
//如:http://localhost:3000?proxyIp=http://1.1.1.1将被代理到http://1.1.1.1
if(req.headers.referer) {
const hostUrl = new URL(req.headers.referer);
const proxyIp = hostUrl.searchParams.get('proxyIp');
if(proxyIp) return proxyIp;
}
},
onProxyReqWs(proxyReq, req, socket) {
//代理socket
proxyReq.on('upgrade', function(proxyRes, proxySocket, proxyHead) {
proxySocket.on('data', (data) => {
socket.write(data);
});
});
},
onError(err, req, res, target) {
//错误监听
res?.writeHead?.(500, {
'Content-Type': 'text/plain',
});
res?.end(err.message);
},
onProxyReq: async (proxyReq, req, res) => {
//监听、重写请求头
const bodyBuffer = Buffer.from(JSON.stringify(req.body));
proxyReq.setHeader('Content-Length', bodyBuffer.length);
proxyReq.write(bodyBuffer);
},
onProxyRes: (proxyRes, req, res) => {
//监听、重写返回结果
return responseInterceptor(async (buffer, proxyRes, req, res) => {
//响应内容
let responseTxt = buffer.toString('utf8');
return buffer;
})(proxyRes, req, res)
},
}
// 定义 context 函数
const contextFunction = (contextPath, req) => {
//不代理的路径
const localPaths = ['register.json', 'updateDhopPort'];
const isLocal = localPaths.find((item) => req.url.includes(item));
if (isLocal && req.method === 'GET') return false;
return true;
};
// 创建反向代理服务
const proxy = createProxyMiddleware(contextFunction, options);
// 定义 context 函数
const server = app.use(proxy);
// 启动服务
app.listen(8080, function () {
console.log([
'代理服务已启动',
`设备地址${serverInfo.ip}`,
`请将proxy、cgi等所有与设备相关的地址修改为:http://localhost:${PORT}`
].join(","));
});
app.get('/otherIp',(req, res) => {
createProxy({
targetUrl: `http://localhost:123`,
errorTips: [
`访问失败`,
],
req,
res
});
});
// 代理中间件函数
function createProxy({ targetUrl, errorTips, req, res }) {
const target = url.parse(targetUrl);
const options = {
hostname: target.hostname,
port: target.port || (target.protocol === 'https:' ? 443 : 80),
path: req.originalUrl,
method: req.method,
headers: req.headers
};
// 移除可能引起问题的头部
delete options.headers.host;
delete options.headers.connection;
const proxyReq = (target.protocol === 'https:' ? https : http).request(options, (proxyRes) => {
// 设置响应头
res.writeHead(proxyRes.statusCode, proxyRes.headers);
proxyRes.pipe(res);
});
// 处理错误
proxyReq.on('error', (err) => {
console.error('Proxy error:', err);
res.writeHead(500, { 'Content-Type': 'text/html; charset=utf-8' });
res.end([
`失败:${err.message}`,
`代理信息:${JSON.stringify(options, null, 4)}`,
...errorTips,
].join(','));
});
// 将请求体转发到目标服务器
req.pipe(proxyReq);
}
各位还有其他方法吗,评论区留言。