Node.js:HTTP服务用request模块返回请求内容报错求助
你的需求完全可行!附错误修复方案
嗨,首先明确:你的需求是完全可以实现的,本质就是做一个简单的反向代理——把客户端发来的请求转发到目标URL,再把目标URL返回的内容原样(或加工后)回传给客户端。
接下来帮你排查ERR_STREAM_WRITE_AFTER_END这个错误,主要踩了几个坑:
错误根源拆解
- 全局变量导致请求冲突:你用了
out_res = res但没加let/const声明,这会让out_res变成全局变量。如果同时有多个客户端发请求,后面的请求会覆盖前面的out_res,结果就是某个请求的响应流被多次调用end(),直接触发ERR_STREAM_WRITE_AFTER_END。 - 响应头写法错误:
out_res.writeHead(200, {res});这里第二个参数应该是标准的响应头对象(比如{'Content-Type': 'text/html'}),你直接传{res}会生成一个无效的响应头,可能引发流状态异常。 - 缺失错误处理:如果
make_request里的请求失败(比如目标URL挂了),你没做任何错误处理就直接写响应,也可能导致响应流异常终止。
修复后的完整代码
我帮你重构了代码,解决了上述问题,同时优化了逻辑:
const http = require("http"); const request = require("request"); // 替换成你实际要转发的目标URL const TARGET_URL = "https://example.com"; const server = http.createServer((req, res) => { // 直接在请求回调里处理,避免全局变量冲突 make_request((err, proxyRes, body) => { // 先处理请求错误的情况 if (err) { res.writeHead(500, {'Content-Type': 'text/plain'}); res.write(`转发请求出错: ${err.message}`); return res.end(); } // 转发目标URL的响应头,过滤掉不需要的Connection头 const responseHeaders = {...proxyRes.headers}; delete responseHeaders['Connection']; // 写入正确的状态码和响应头 res.writeHead(proxyRes.statusCode, responseHeaders); // 把目标URL返回的内容写给客户端 res.write(body); res.end(); }); }); function make_request(callback) { request(TARGET_URL, callback); } // 启动服务器,加上回调确认启动状态 server.listen(8080, () => { console.log('服务器已启动,监听端口8080'); });
额外小贴士
request模块已停止维护:request在2020年就废弃了,建议换成更现代的库,比如axios或者node-fetch(Node.js 18及以上版本已经内置fetch,不用额外安装)。给你个node-fetch的示例:const http = require("http"); const fetch = require('node-fetch'); // Node.js <18需要执行npm install node-fetch const TARGET_URL = "https://example.com"; const server = http.createServer(async (req, res) => { try { const proxyRes = await fetch(TARGET_URL); const body = await proxyRes.text(); const responseHeaders = {...proxyRes.headers}; delete responseHeaders['Connection']; res.writeHead(proxyRes.status, responseHeaders); res.write(body); res.end(); } catch (err) { res.writeHead(500, {'Content-Type': 'text/plain'}); res.write(`转发请求出错: ${err.message}`); res.end(); } }); server.listen(8080, () => { console.log('服务器已启动,监听端口8080'); });- 支持动态转发:如果需要根据客户端请求的路径(比如
http://localhost:8080/api/user)动态转发到目标URL的对应路径,可以用req.url拼接,比如const fullTargetUrl = TARGET_URL + req.url。
内容的提问来源于stack exchange,提问作者NeoZoom.lua
相关产品推荐
相关产品推荐

