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

Remix上传大体积视频至S3报MaxPartSizeExceededError解决方案

问题背景

在Remix框架下实现视频上传功能,参考官方示例完成基础开发后,小体积图片可正常上传,但上传大体积视频时触发如下报错:

MaxPartSizeExceededError: Field "file" exceeded upload size of 3000000 bytes.

当前实现的表单与Action代码如下:

export const action: ActionFunction = async ({ request, params }) => {
  const uploadHandler: UploadHandler = composeUploadHandlers(
    s3UploadHandler,
    createMemoryUploadHandler()
  );
  const formData = await parseMultipartFormData(request, uploadHandler);
  const newDesc = formData.get("title");
  const newFile = formData.get("file");
  
  return json({
    newDesc,
    newFile,
  });
}

const Create = () => {
  const [asset, setAsset] = useState<File | null>(null);
  const [title, setTitle] = useState('');

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setTitle(event.target.value);
  };

  const onChangeAsset = async (evt) => {
    const file = evt?.target?.files?.[0]
    if (!file) return setAsset(null)
    setAsset(file)
  }

  return (
  <Box>
    <Form method="post" action='/create' encType="multipart/form-data">
      {/* 文件上传组件 */}
      <Upload
        sublabel='Add video to upload to S3'
        name='asset'
        onChange={onChangeAsset}
        value={asset}
        maxSize={52000000000}
      />
      
      {/* 文本输入组件 */}
      <TextField
        name='title'
        label="Title"
        value={title}
        onChange={handleChange}
      />

      <Button type='submit'>Submit</Button>
    </Form>
  </Box>
  )
}

export default Create

查阅官方文档可见createMemoryUploadHandler的说明如下:

配置项: 该API仅支持maxPartSize和filter两个配置项,用法与unstable_createFileUploadHandler一致,不推荐在大规模生产场景使用,仅适合简单场景下的便捷调用。


解决方案

报错核心原因是createMemoryUploadHandler默认单分片大小限制为3MB,即报错提示的3000000字节,且该处理器将所有上传内容存在服务端内存中,本身就不适合处理大体积文件,否则极易触发服务端内存溢出。可选实现方案如下:

方案1:使用本地临时文件上传处理器(适合百兆内视频、部署环境有可写磁盘的场景)

弃用默认配置的内存处理器,换成Remix内置的文件上传处理器,将上传分片先写入服务端本地临时目录,避免占用内存,同时手动配置匹配业务需求的大小限制:

  • 首先修复代码里的字段名不匹配问题:当前上传组件的name属性值为asset,但Action中通过formData.get("file")取值,二者对齐才能正常拿到文件对象
  • 引入unstable_createFileUploadHandler替换内存处理器,配置示例:
import { unstable_createFileUploadHandler as createFileUploadHandler } from "@remix-run/node";

export const action: ActionFunction = async ({ request, params }) => {
  const uploadHandler: UploadHandler = composeUploadHandlers(
    s3UploadHandler,
    createFileUploadHandler({
      maxPartSize: 52000000000, // 和前端上传组件的maxSize保持一致,单位为字节
      directory: "./tmp/uploads", // 临时文件存储目录,需确保部署环境有写入权限
      filter: ({ name }) => name !== "asset" // 非文件字段走内存处理,文件字段走自定义s3UploadHandler
    })
  );
  const formData = await parseMultipartFormData(request, uploadHandler);
  const newDesc = formData.get("title");
  const newFile = formData.get("asset"); // 字段名和前端name对齐
  
  return json({
    newDesc,
    newFile,
  });
}

注意:该方案不支持只读磁盘的Serverless部署环境,大文件上传时长时间占用服务端连接,超过500M的视频不推荐用这种中转上传模式

方案2:S3预签名直传(生产环境大体积视频推荐方案)

完全绕开Remix服务端的上传中转逻辑,让客户端直接将文件上传到S3,从根源避免服务端解析大小限制、内存/磁盘占用、连接超时问题,实现流程:

  • 新增一个专门生成S3预签名上传URL的Action,预签名规则中可自定义允许上传的最大文件体积、文件类型、URL过期时间
  • 前端提交表单时,先请求该接口拿到预签名URL,将选中的视频文件直接通过PUT请求上传到S3,拿到文件最终的S3访问地址
  • 前端再将视频的S3地址、标题等其他表单字段提交给业务Action,完成数据落库等后续逻辑
  • 若需要支持几十G的超大文件、断点续传能力,可搭配S3的分片上传API实现前端分片上传,上传稳定性和速度远高于服务端中转模式

常见踩坑点
  • 如果服务前挂了Nginx、CDN等反向代理,需要同步调整代理层的最大请求体限制,否则请求会在到达Remix服务前被代理拦截
  • 即便调大maxPartSize参数,也不要用createMemoryUploadHandler处理超过100M的文件,否则极易触发服务端OOM崩溃
  • 用预签名直传方案时,一定要在预签名规则里严格限制文件类型、大小,避免被恶意利用上传违规文件到S3存储桶

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 00:54:39