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

如何用Node.js本地服务器镜像其他网站?遇AggregateError问题求解

问题分析与解决方案

当前实现的问题

你的现有代码存在以下几个关键问题,也是导致批量请求出错的主要原因:

  • IPv6连接失败:Node.js默认优先尝试IPv6地址,但你的本地网络可能未启用IPv6支持,当批量请求(如加载MP3、GLB等资源时浏览器会并发请求多个文件)时,多次IPv6连接失败触发AggregateError。
  • 内存占用过高:使用arraybuffer会将整个资源加载到内存中,大文件(如音频、3D模型)批量请求时会导致内存压力骤增,进一步加剧连接问题。
  • 请求/响应头不完整:没有转发原请求的关键头信息(如User-Agent、Accept等),也没有完整转发目标服务器的响应头(如缓存控制、跨域头),可能导致目标服务器拒绝请求或资源加载异常。
  • 错误处理不完善:仅打印错误但未向客户端返回合适的错误响应,也没有重试逻辑。

修复与正确实现方案

1. 解决IPv6连接问题

在Axios配置中强制使用IPv4,避免因网络不支持IPv6导致的连接失败:

const axios = require('axios');
const dns = require('dns');

// 创建强制IPv4的Axios实例
const axiosInstance = axios.create({
  dnsLookup: (hostname, options, callback) => {
    dns.lookup(hostname, { ...options, family: 4 }, callback);
  },
  responseType: 'stream' // 改用流式传输降低内存占用
});

2. 正确的Express镜像服务器实现

使用流式传输减少内存占用,完整转发请求/响应头,支持所有HTTP方法:

const express = require('express');
const axios = require('axios');
const dns = require('dns');
const app = express();
const targetUrl = 'https://parking-master.github.io/FPS';

// 创建强制IPv4的Axios实例
const axiosInstance = axios.create({
  dnsLookup: (hostname, options, callback) => {
    dns.lookup(hostname, { ...options, family: 4 }, callback);
  },
  responseType: 'stream',
  maxRedirects: 5
});

// 处理所有HTTP方法的请求
app.all('*', async (req, res) => {
  const targetPath = req.url === '/' ? '' : req.url;
  const fullTargetUrl = `${targetUrl}${targetPath}`;

  try {
    // 转发原请求头,排除不需要的host字段
    const headers = { ...req.headers };
    delete headers.host;

    const response = await axiosInstance({
      method: req.method,
      url: fullTargetUrl,
      headers: headers,
      data: req.method !== 'GET' && req.method !== 'HEAD' ? req : undefined
    });

    // 转发目标服务器的响应头
    res.set(response.headers);
    // 设置响应状态码
    res.status(response.status);
    // 流式传输响应内容,避免内存溢出
    response.data.pipe(res);

    // 处理流式传输中的错误
    response.data.on('error', (err) => {
      console.error('Stream error:', err);
      res.status(500).send('Internal Server Error');
    });
  } catch (err) {
    console.error('Request error:', err);
    // 向客户端返回对应错误状态码
    res.status(err.response?.status || 500).send(err.message || 'Internal Server Error');
  }
});

const PORT = 8080;
app.listen(PORT, () => {
  console.log(`Mirror server running on http://localhost:${PORT}`);
});

3. 额外优化建议

  • 添加缓存策略:使用express-cache-controller中间件缓存静态资源,减少重复请求。
  • 限制并发请求数:用p-limit库限制批量请求的并发数,避免触发目标服务器限流。
  • 处理跨域:添加cors中间件支持跨域访问。

总结

你的初始实现思路方向正确,但缺少关键细节处理(如IPv4强制、流式传输、头信息转发),导致批量请求时出现错误。上面的实现解决了这些问题,能够稳定镜像目标网站,同时支持大文件和批量请求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 04:43:30