You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

本地localhost运行Node.js HTTPS代理返回ERR_EMPTY_RESPONSE空响应问题

问题背景

个人项目开发需要拦截本机发往外部服务器的所有HTTP/HTTPS请求(覆盖浏览器、curl等工具发起的请求),部分场景需根据请求主机名将请求重定向至自定义页面。
为验证请求拦截与转发的逻辑可行性,基于Node.js搭建简易HTTPS代理服务,预期功能为打印每个请求的相关信息后,将请求转发至原始目标地址,核心实现代码如下:

var https = require('https');
var httpProxy = require('http-proxy');
var fs = require('fs');
var path = require('path');

const options = {
    ssl: {
      key: fs.readFileSync(path.resolve(__dirname, './mycert.key'), 'utf8'),
      cert: fs.readFileSync(path.resolve(__dirname, './mycert.crt'), 'utf8')
    },
    secure: false,
    toProxy: true
  }
const proxy = httpProxy.createProxyServer(options);

const httpsServer = https.createServer(options.ssl, (req, res) => {
    console.log("WEBSERVER")
    console.log(req.headers.host);
    proxy.web(req, res, {
      target: req.headers.host,
    })
})

const httpsListener = httpsServer.listen(8080);

console.log("LISTENING ON 8080")
现存异常
  • 将Windows系统代理设置指向该本地代理服务后,浏览器发起的所有请求均返回ERR_EMPTY_RESPONSE错误,代理运行控制台无任何日志输出
  • 直接向该代理地址发起HTTPS请求时,控制台可正常打印请求信息,但无法完成请求转发
  • 不确定localhost环境是否支持搭建该类代理服务,需要可行的排查思路与解决方案
排查思路与解决方案

localhost环境完全支持搭建这类代理服务,问题出在代理实现逻辑不符合正向代理的协议规范,和运行环境无关。

核心错误原因

正向代理处理HTTP和HTTPS请求的逻辑和普通Web服务完全不同,当前实现完全没匹配代理协议要求:

  • 正向代理默认以HTTP协议对外提供服务,不需要给代理服务本身提前配置SSL证书。HTTPS请求不会直接发HTTPS请求到代理,而是先发送CONNECT方法的明文请求,要求代理建立到目标服务器的TCP隧道,隧道建立后才会走TLS加密流量。当前实现只启动了HTTPS服务,客户端发明文CONNECT请求时直接TLS握手失败,服务端收不到合法请求自然没有日志,客户端直接收到空响应。
  • 没有实现CONNECT方法的处理逻辑,无法建立HTTPS请求需要的转发隧道。
  • 转发配置错误:target参数仅传req.headers.host缺少协议前缀,且toProxy参数仅在转发目标是另一个代理服务时才需要开启,直接转发到目标站点时开启该参数会导致转发逻辑异常。
  • 没有启动HTTP服务监听,系统代理转发的明文HTTP请求无法被处理。

修复步骤

  1. 去掉代理服务本身的SSL配置,先启动HTTP服务作为代理入口,同时处理普通HTTP请求和HTTPS的CONNECT隧道请求。
  2. 新增CONNECT方法的处理逻辑:收到CONNECT请求后,和目标服务器建立TCP连接,向客户端返回隧道建立成功响应,再将客户端socket和目标服务器socket做双向管道转发,实现基础流量透传。
  3. 修正转发参数:HTTP请求转发时给target补全http://协议前缀,移除错误的toProxy: true配置,添加转发错误处理避免服务崩溃。
  4. 如果需要打印HTTPS请求明文、做请求重定向,不能用普通透传隧道,需要实现中间人(MITM)逻辑:收到CONNECT请求后,不直接建立到目标站点的TCP隧道,而是用提前生成的自签CA动态签发当前请求域名的证书,和客户端完成TLS握手拿到明文请求内容,处理完打印、重定向逻辑后,再由代理和目标站点建立TLS连接转发请求。注意使用该模式需要提前把自签CA安装到系统、浏览器的信任根证书列表中,否则会触发证书安全警告。

最小可运行基础透传代理代码

const http = require('http');
const net = require('net');
const httpProxy = require('http-proxy');

const proxy = httpProxy.createProxyServer({
  secure: false
});

// 处理普通HTTP请求
const proxyServer = http.createServer((req, res) => {
  console.log('[HTTP请求]', req.method, req.url, `Host: ${req.headers.host}`);
  proxy.web(req, res, {
    target: `http://${req.headers.host}`
  }, (err) => {
    console.error('HTTP请求转发失败:', err.message);
    res.writeHead(502);
    res.end('Bad Gateway');
  });
});

// 处理HTTPS CONNECT隧道请求
proxyServer.on('connect', (req, clientSocket, head) => {
  console.log('[HTTPS隧道建立]', req.url);
  const [targetHost, targetPort] = req.url.split(':');
  const port = Number(targetPort) || 443;

  const serverSocket = net.connect(port, targetHost, () => {
    clientSocket.write('HTTP/1.1 200 Connection Established\r\n\r\n');
    serverSocket.write(head);
    // 双向流量透传
    serverSocket.pipe(clientSocket);
    clientSocket.pipe(serverSocket);
  });

  // 连接错误处理
  clientSocket.on('error', () => serverSocket.destroy());
  serverSocket.on('error', () => clientSocket.destroy());
});

proxyServer.listen(8080, () => {
  console.log('代理服务已启动,监听 127.0.0.1:8080');
});

注意:上述代码仅实现基础流量透传,HTTPS流量是加密传输的,服务端无法读取明文内容。如果需要实现HTTPS请求拦截、内容修改、重定向,需要在CONNECT处理阶段接入中间人TLS解密逻辑,可基于node-forge等库实现动态证书签发能力。


内容的提问来源于stack exchange,提问作者Lior Dahan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 06:09:20