用 Node.js 原生 API 写个本地代理解决跨域烦恼前后端分离开发时最让人头疼的往往不是业务逻辑而是浏览器的同源策略。前端跑在localhost:3000后端在localhost:8080一旦前端发起 AJAX 请求控制台立马飘红CORS 报错拦路。很多同事为了省事直接在后台配置Access-Control-Allow-Origin: *。这在本地调试没问题但上线前如果忘了收回来生产环境就是个大漏洞。与其在两边反复横跳改配置不如在本地起个轻量级的代理网关。用 Node.js 原生http模块就能写零依赖还能顺便把请求头给洗了。为什么需要这个代理本地开发时前后端端口不同浏览器默认禁止跨域访问。如果不做处理前端请求会被拦截。如果为了图方便在后端直接放行所有跨域又会给生产环境埋下 XSS 隐患。更麻烦的是没有中间层你很难统一查看请求的转发耗时排查问题全靠猜。这个代理的作用很简单前端请求先发给它它再转给后端。浏览器以为是在跟同源服务器通信自然就放行了。代理是怎么工作的流程并不复杂核心就是“截获 - 重写 - 转发”。截获请求前端请求localhost:9000代理程序接收到。重写头部把Origin、Host等头部改成后端能识别的样子避免后端微服务因为校验 Origin 而拒绝请求。转发请求代理向后端localhost:8080发起真实的 HTTP 请求。注入响应头拿到后端返回的数据后手动加上Access-Control-Allow-Origin: *等跨域头。返回前端把处理好的数据流式写回给前端。如果后端 5 秒内没反应代理直接返回 504避免前端页面卡死。代码实现下面这个脚本完全基于 Node.js 原生http和url模块没有引入http-proxy-middleware这种第三方包。代码量不大但包含了超时控制、流式转发和基础的路由处理。// dev_proxy_gateway.js const http require(http); const url require(url); const TARGET_API_SERVER http://127.0.0.1:8080; // 后端真实地址 const PROXY_PORT 9000; // 代理监听端口 function logging(msg) { console.log(\x1b[36m[Proxy] ${msg}\x1b[0m); } const server http.createServer((req, res) { logging(${req.method} ${req.url}); // 1. 处理 OPTIONS 预检请求 if (req.method OPTIONS) { res.writeHead(204, { Access-Control-Allow-Origin: *, Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS, Access-Control-Allow-Headers: Content-Type, Authorization, Access-Control-Max-Age: 86400 }); return res.end(); } // 2. 构造转发请求 const parsedTarget url.parse(TARGET_API_SERVER); const options { hostname: parsedTarget.hostname, port: parsedTarget.port, path: req.url, method: req.method, headers: { ...req.headers, host: ${parsedTarget.hostname}:${parsedTarget.port}, origin: TARGET_API_SERVER, referer: TARGET_API_SERVER }, timeout: 5000 // 5 秒超时 }; // 3. 发起代理请求 const proxyReq http.request(options, (proxyRes) { // 注入跨域头 res.setHeader(Access-Control-Allow-Origin, *); res.setHeader(Access-Control-Allow-Methods, GET, POST, PUT, DELETE, OPTIONS); res.setHeader(Access-Control-Allow-Headers, Content-Type, Authorization); res.writeHead(proxyRes.statusCode, proxyRes.headers); // 4. 流式透传数据 proxyRes.pipe(res); }); // 5. 错误与超时处理 proxyReq.on(error, (err) { logging(Error: ${err.message}, error); res.writeHead(504, { Content-Type: application/json }); res.end(JSON.stringify({ error: Gateway Timeout: Backend unreachable. })); }); proxyReq.on(timeout, () { proxyReq.destroy(); res.writeHead(504, { Content-Type: application/json }); res.end(JSON.stringify({ error: Gateway Timeout: Backend no response within 5s. })); }); // 把前端的数据管道写入代理请求 req.pipe(proxyReq); }); server.listen(PROXY_PORT, () { logging(Proxy running on http://127.0.0.1:${PROXY_PORT}); logging(Forwarding to: ${TARGET_API_SERVER}); });几个需要注意的地方这套方案虽然轻量但在实际使用中也有几个局限性得提前心里有数延迟问题请求多了一层转发理论上会增加几毫秒的延迟。但在本地环境下这点损耗通常 5ms相比解决跨域带来的便利完全可以忽略。HTTPS 支持如果前端项目强制 HTTPS代理网关也得配自签名证书。本地调试建议在浏览器里直接允许“不安全连接”没必要为了个开发工具去折腾复杂的证书链。长连接支持上面的代码只处理了普通的 HTTP 请求。如果项目里有 WebSocket 或 SSE服务端推送原生http模块不会自动升级协议。这时候需要显式监听upgrade事件手动把 TCP socket 桥接过去否则实时功能会失效。总结在本地起个 Node.js 代理是解决跨域最稳妥的办法。它比在后端直接放行安全比配 Nginx 轻量。代码不多维护成本低能帮你把精力从“为什么请求被拦截”这种琐事上解放出来专心写业务逻辑。
用 Node.js 原生 API 写个本地代理,解决跨域烦恼
用 Node.js 原生 API 写个本地代理解决跨域烦恼前后端分离开发时最让人头疼的往往不是业务逻辑而是浏览器的同源策略。前端跑在localhost:3000后端在localhost:8080一旦前端发起 AJAX 请求控制台立马飘红CORS 报错拦路。很多同事为了省事直接在后台配置Access-Control-Allow-Origin: *。这在本地调试没问题但上线前如果忘了收回来生产环境就是个大漏洞。与其在两边反复横跳改配置不如在本地起个轻量级的代理网关。用 Node.js 原生http模块就能写零依赖还能顺便把请求头给洗了。为什么需要这个代理本地开发时前后端端口不同浏览器默认禁止跨域访问。如果不做处理前端请求会被拦截。如果为了图方便在后端直接放行所有跨域又会给生产环境埋下 XSS 隐患。更麻烦的是没有中间层你很难统一查看请求的转发耗时排查问题全靠猜。这个代理的作用很简单前端请求先发给它它再转给后端。浏览器以为是在跟同源服务器通信自然就放行了。代理是怎么工作的流程并不复杂核心就是“截获 - 重写 - 转发”。截获请求前端请求localhost:9000代理程序接收到。重写头部把Origin、Host等头部改成后端能识别的样子避免后端微服务因为校验 Origin 而拒绝请求。转发请求代理向后端localhost:8080发起真实的 HTTP 请求。注入响应头拿到后端返回的数据后手动加上Access-Control-Allow-Origin: *等跨域头。返回前端把处理好的数据流式写回给前端。如果后端 5 秒内没反应代理直接返回 504避免前端页面卡死。代码实现下面这个脚本完全基于 Node.js 原生http和url模块没有引入http-proxy-middleware这种第三方包。代码量不大但包含了超时控制、流式转发和基础的路由处理。// dev_proxy_gateway.js const http require(http); const url require(url); const TARGET_API_SERVER http://127.0.0.1:8080; // 后端真实地址 const PROXY_PORT 9000; // 代理监听端口 function logging(msg) { console.log(\x1b[36m[Proxy] ${msg}\x1b[0m); } const server http.createServer((req, res) { logging(${req.method} ${req.url}); // 1. 处理 OPTIONS 预检请求 if (req.method OPTIONS) { res.writeHead(204, { Access-Control-Allow-Origin: *, Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS, Access-Control-Allow-Headers: Content-Type, Authorization, Access-Control-Max-Age: 86400 }); return res.end(); } // 2. 构造转发请求 const parsedTarget url.parse(TARGET_API_SERVER); const options { hostname: parsedTarget.hostname, port: parsedTarget.port, path: req.url, method: req.method, headers: { ...req.headers, host: ${parsedTarget.hostname}:${parsedTarget.port}, origin: TARGET_API_SERVER, referer: TARGET_API_SERVER }, timeout: 5000 // 5 秒超时 }; // 3. 发起代理请求 const proxyReq http.request(options, (proxyRes) { // 注入跨域头 res.setHeader(Access-Control-Allow-Origin, *); res.setHeader(Access-Control-Allow-Methods, GET, POST, PUT, DELETE, OPTIONS); res.setHeader(Access-Control-Allow-Headers, Content-Type, Authorization); res.writeHead(proxyRes.statusCode, proxyRes.headers); // 4. 流式透传数据 proxyRes.pipe(res); }); // 5. 错误与超时处理 proxyReq.on(error, (err) { logging(Error: ${err.message}, error); res.writeHead(504, { Content-Type: application/json }); res.end(JSON.stringify({ error: Gateway Timeout: Backend unreachable. })); }); proxyReq.on(timeout, () { proxyReq.destroy(); res.writeHead(504, { Content-Type: application/json }); res.end(JSON.stringify({ error: Gateway Timeout: Backend no response within 5s. })); }); // 把前端的数据管道写入代理请求 req.pipe(proxyReq); }); server.listen(PROXY_PORT, () { logging(Proxy running on http://127.0.0.1:${PROXY_PORT}); logging(Forwarding to: ${TARGET_API_SERVER}); });几个需要注意的地方这套方案虽然轻量但在实际使用中也有几个局限性得提前心里有数延迟问题请求多了一层转发理论上会增加几毫秒的延迟。但在本地环境下这点损耗通常 5ms相比解决跨域带来的便利完全可以忽略。HTTPS 支持如果前端项目强制 HTTPS代理网关也得配自签名证书。本地调试建议在浏览器里直接允许“不安全连接”没必要为了个开发工具去折腾复杂的证书链。长连接支持上面的代码只处理了普通的 HTTP 请求。如果项目里有 WebSocket 或 SSE服务端推送原生http模块不会自动升级协议。这时候需要显式监听upgrade事件手动把 TCP socket 桥接过去否则实时功能会失效。总结在本地起个 Node.js 代理是解决跨域最稳妥的办法。它比在后端直接放行安全比配 Nginx 轻量。代码不多维护成本低能帮你把精力从“为什么请求被拦截”这种琐事上解放出来专心写业务逻辑。