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

如何在Fastify 2.15中实现Multipart文件上传代理网关

问题描述

我基于Fastify实现了一个后端网关代理服务器,所有请求通过Axios转发,但处理Multipart请求时失败,请求无法到达后端。

代理服务器配置

网关中使用fastify-multipart插件:

app.register(require("fastify-multipart"), { addToBody: true });

请求处理逻辑

handle : async (request) => {
  
 const formData = new FormData();
    const keys = Object.keys(JSON.parse(request.body))
    const buffer = JSON.parse(request.body)[keys[0]][0]
    formData.append('my_field', keys[0]);
    formData.append('my_buffer', buffer.data.data[0]);

config = {
      qs : queryStringParameters,
      method : 'POST',
      headers : { 
        "Content-Type" : headersNormalized['content-type'],
        "User-Agent" : headersNormalized['user-agent'],
        "client-version": headersNormalized['androidversionname'],
        "Content-Length": headersNormalized['content-length'],
      },
      body: formData,
      raw : true
    }

    const { status, data } = await http(request).LB("/downstream/upload", config)
}

当前尝试转发接收的.png文件(网关接收后封装为Multipart格式发送),但后端服务器始终返回500错误。后端服务器同样使用fastify-multipart插件:

app.register(require("fastify-multipart"));

需要指导如何基于Fastify和Node.js实现Multipart文件上传代理网关。


解决方案

核心问题分析

当前实现存在几个关键错误:

  • 启用addToBody: true会把Multipart请求解析为JSON格式,破坏原始的Multipart结构,导致重构时数据格式错误
  • 手动解析request.body并重构FormData的方式丢失了文件元数据(如文件名、MIME类型),后端无法正确解析
  • 强行设置原始Content-Length和Content-Type,与新构建的FormData不匹配,引发后端解析失败

正确实现步骤

1. 调整网关端fastify-multipart配置

关闭addToBody,直接保留原始Multipart流,避免解析破坏结构:

// 网关端插件注册
app.register(require("fastify-multipart"), {
  limits: {
    fileSize: 10 * 1024 * 1024 // 根据业务需求调整文件大小限制
  }
});

2. 网关端转发Multipart请求的正确逻辑

直接转发原始请求流,保证数据格式完全一致,这是最可靠的方式:

handle: async (request) => {
  // 构建转发用的请求头,排除自动生成的字段
  const forwardHeaders = {
    ...request.headers,
    'content-length': undefined, // 让Axios自动计算长度
    'host': 'your-downstream-server-host' // 替换为实际后端服务的Host
  };

  const config = {
    method: 'POST',
    url: '/downstream/upload',
    baseURL: 'http://your-downstream-server-url', // 替换为实际后端地址
    headers: forwardHeaders,
    data: request.raw, // 直接转发原始请求流
    responseType: 'stream' // 禁用自动解析,保持流的原始状态
  };

  try {
    const { status, data } = await axios(config);
    return { status, data };
  } catch (error) {
    console.error('转发失败:', error);
    throw error;
  }
}

3. 后端服务器配置(无需修改)

后端继续使用fastify-multipart即可,示例处理路由如下:

app.register(require("fastify-multipart"));

// 后端处理上传的示例路由
app.post('/downstream/upload', async (request, reply) => {
  const parts = await request.parts();
  for await (const part of parts) {
    if (part.file) {
      // 处理文件流
      const buffer = await part.toBuffer();
      console.log(`接收文件: ${part.filename}, 大小: ${buffer.length} bytes`);
      // 这里可以添加文件保存或业务处理逻辑
    } else {
      // 处理普通表单字段
      console.log(`字段: ${part.fieldname}, 值: ${part.value}`);
    }
  }
  reply.send({ status: 'success' });
});

替代方案:需修改Multipart内容时的正确写法

如果必须在网关中修改Multipart内容,需保留完整的文件元数据:

handle: async (request) => {
  const formData = new FormData();
  const parts = await request.parts();

  // 遍历原始Multipart的所有部分,完整保留元数据
  for await (const part of parts) {
    if (part.file) {
      const buffer = await part.toBuffer();
      // 正确添加文件到FormData,保留文件名和MIME类型
      formData.append(part.fieldname, buffer, {
        filename: part.filename,
        contentType: part.mimetype
      });
    } else {
      // 添加普通表单字段
      formData.append(part.fieldname, part.value);
    }
  }

  // 可在此添加自定义字段(如果需要)
  formData.append('my_field', 'custom_value');

  const config = {
    method: 'POST',
    url: '/downstream/upload',
    baseURL: 'http://your-downstream-server-url',
    // 让FormData自动生成包含boundary的正确Content-Type
    headers: {
      ...formData.getHeaders(),
      'User-Agent': request.headers['user-agent'],
      'client-version': request.headers['androidversionname']
    },
    data: formData
  };

  const { status, data } = await axios(config);
  return { status, data };
}

关键注意事项

  • 不要手动设置Content-Type和Content-Length,让Axios或FormData自动处理,避免boundary不匹配
  • 优先使用原始请求流转发,减少数据解析和重构带来的错误
  • 确保网关和后端的fastify-multipart版本兼容,避免解析逻辑差异

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 16:55:19