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

Node.js中用undici的ProxyAgent配合fetch无响应(Axios正常)

使用undici ProxyAgent配合fetch发起代理请求无响应,其他工具正常

问题描述

在Node.js项目中尝试用undici的ProxyAgent配合原生fetch发起带代理的GET请求,但请求既不resolve也不reject,代理代码里的第一个console.log完全没执行。但用Axios、http.get甚至Postman都能正常通过该代理请求。想知道是不是操作有误?undici的代理是否只支持特定类型的代理?

运行环境:Node.js LTS 20.17.0(也试过18.18.2)


相关代码

测试代码 index.js

import { ProxyAgent } from "undici";

const client = new ProxyAgent("http://127.0.0.1:8000");

fetch("http://ifconfig.io/ip", {
  dispatcher: client,
  method: "GET",
})
  .then((response) => {
    console.log("Got response");
    if (!response.ok) {
      throw Error("response not ok");
    }
    return response.text();
  })
  .then((data) => {
    console.log("Response Data = ", data);
  })
  .catch((error) => {
    console.error("Error occurred:", error.message);
  });

本地代理服务 proxy.js(兼容Axios和Postman)

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

// 创建代理服务器
const proxy = httpProxy.createProxyServer({});

// 创建HTTP服务器并使用代理
const server = http.createServer((req, res) => {
  console.log("Original request URL:", req.url);
  
  const parsedUrl = url.parse(req.url, true);
  // 直接设置目标为后端服务
  const target = `${parsedUrl.protocol}//${parsedUrl.host}`; 

  // 将请求代理到目标服务器
  proxy.web(req, res, { target });

  // 记录代理请求
  console.log(`Proxied request to: ${target}`);
});

// 监听端口8000
const PORT = 8000;
server.listen(PORT, () => {
  console.log(`动态代理服务器运行在 http://localhost:${PORT}`);
});

package.json

{
  "name": "nodejs-proj",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "type":"module",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "axios": "^1.7.4",
    "http-proxy": "^1.18.1",
    "http-proxy-agent": "^7.0.2",
    "undici": "^6.19.8"
  }
}

Axios正常工作示例 indexAxios.js

import axios from "axios";

axios.get('https://ifconfig.io/ip', {
  proxy: {
    protocol: "http",
    host: '127.0.0.1',
    port: 8000,
  }
})
  .then(response => {
    console.log('Response data:', response.data);
  })
  .catch(error => {
    console.error('Error occurred:', error.message);
  });

其他测试过的代理实现(同样兼容Axios但不兼容undici fetch)

基于request模块的代理

import http from "http";
import request from "request";

const PORT = 8000;

http.createServer(function (req, res) {
  console.log(`Incoming request to ${req.url}`);
  req.pipe(request(req.url)).pipe(res);
}).listen(PORT);

基于proxy模块的代理

import * as http from 'http';
import { createProxy } from 'proxy';

const server = createProxy(http.createServer());

// 记录每个入站请求
server.on('request', (req, res) => {
  console.log(`Incoming request: ${req.method} ${req.url}`);
});

server.listen(3128, () => {
  var port = server.address().port;
  console.log('HTTP(s) proxy server listening on port %d', port);
});

问题原因与解决方法

核心问题

undici的ProxyAgent遵循HTTP代理标准,会直接向代理服务器发送完整的目标URL作为请求路径(比如GET http://ifconfig.io/ip HTTP/1.1),而你的本地代理服务器只处理了Axios等工具发送的相对路径请求,无法识别这种绝对URI格式的请求,导致请求卡住。

具体修复方案

方案1:修改本地代理服务器,支持绝对路径请求

调整proxy.js的逻辑,兼容undici发送的绝对URI请求:

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

const proxy = httpProxy.createProxyServer({});

const server = http.createServer((req, res) => {
  console.log("Original request URL:", req.url);
  
  let target;
  // 处理undici发送的绝对路径URL
  if (req.url.startsWith('http://') || req.url.startsWith('https://')) {
    const parsedUrl = url.parse(req.url);
    target = `${parsedUrl.protocol}//${parsedUrl.host}`;
    // 将请求URL改为相对路径,适配http-proxy的web方法
    req.url = parsedUrl.path;
  } else {
    // 兼容Axios等工具的相对路径请求
    const parsedUrl = url.parse(req.url, true);
    target = `${parsedUrl.protocol}//${parsedUrl.host}`;
  }

  // 添加错误处理,避免请求无响应
  proxy.web(req, res, { target }, (err) => {
    console.error('Proxy error:', err);
    res.writeHead(500);
    res.end('Proxy error');
  });

  console.log(`Proxied request to: ${target}`);
});

const PORT = 8000;
server.listen(PORT, () => {
  console.log(`动态代理服务器运行在 http://localhost:${PORT}`);
});

方案2:使用undici自带fetch的proxy选项

无需手动创建ProxyAgent,直接用undici的fetch内置的proxy配置,内部会自动处理正确的请求格式:

import { fetch } from "undici";

fetch("http://ifconfig.io/ip", {
  method: "GET",
  proxy: "http://127.0.0.1:8000"
})
  .then((response) => {
    console.log("Got response");
    if (!response.ok) {
      throw Error("response not ok");
    }
    return response.text();
  })
  .then((data) => {
    console.log("Response Data = ", data);
  })
  .catch((error) => {
    console.error("Error occurred:", error.message);
  });

额外说明

  • undici的代理实现严格遵循RFC 7230标准,要求代理服务器支持绝对URI请求;如果是HTTPS目标,还需要支持CONNECT方法建立隧道,http-proxy默认支持该方法,自定义代理则需要手动处理。
  • Axios默认采用传统的相对路径代理方式,和undici的标准行为存在差异,这也是为什么前者能正常工作的原因。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 08:29:52