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

Remix.run文件上传问题:Action中File对象变为字符串

Remix表单上传文件时Action中无法识别File对象的问题

我正在开发一个Remix应用,允许用户通过表单上传文件。前端编写了handleSubmit函数处理表单提交,将包含文件的FormData发送到Action,但在Action中接收时,文件变成了字符串,用value instanceof File检查返回false。

前端handleSubmit代码

const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();
        const requiredFields = [
            "projectName",
            "blockchain",
            "supply",
            "mintPrice",
            "mintDate",
            "twitterLink",
            "emailContact",
            "description",
            "teamSummary",
            "teamMembers",
            "references",
            "documents",
            "artwork",
            "marketing",
            "allowlist",
            "investment",
        ];
    const newErrors = {...initialErrors};
    let $form = event.currentTarget;
    let formData = new FormData($form);

    requiredFields.forEach(field => {
        if (!projectForm[field as keyof ProjectFormState]) {
            newErrors[field] = true;
        }
    });

    if (Object.values(newErrors).some(value => value)) {
        setErrors(newErrors);
        return;
    }

    console.log('projectForm', projectForm);

    Object.entries(projectForm).forEach(([key, value]) => {
        console.log('file type in submit', value instanceof File)
        if (value instanceof File) {
            console.log('file value', value)
            formData.append(key, value, value.name);
        } else {
            formData.set(key, value);
        }
    });

    submit(formData, {
        method: $form.getAttribute("method") as HTMLFormMethod ?? $form.method,
        action: $form.getAttribute("action") ?? $form.action,
    });
};

前端日志显示文件是正常的File对象,但在Action中出现问题:

Action代码

export const action = async ({request}: ActionArgs) => {
const formData = await request.formData();
const project: ProjectFormFields = {} as ProjectFormFields;

await Promise.all(Array.from(formData.entries()).map(async ([key, value]) => {
    console.log(key, value); // Log the value of 'value'
    console.log(value instanceof File); // Check whether 'value' is a File instance
    if (value instanceof File) {
        const arrayBuffer = await value.arrayBuffer();
        project[key] = Buffer.from(arrayBuffer);
    } else {
        project[key] = value;
    }
}));

console.log(project)

try {
    const response = await putProjectForm(project);
    const {status} = response;
    console.log('Form submission response', status);

    return redirect("/", {
        headers: {
            "Set-Cookie": `message=Your form was submitted successfully; Path=/;`,
        },
    });

} catch(error) {
    console.error('There was an error with the form submission', error);
}

return null;

console.log(value instanceof File)返回false,无法正确识别文件。


解决方法

1. 服务器端检查Blob而非File

在Remix的Action(Node.js环境)中,上传的文件对象是Blob实例,而不是浏览器端的File对象(File是Blob的子类,但Node.js环境下的FormData实现没有File,只有Blob)。因此需要修改检查逻辑:

// 替换原来的instanceof File检查
if (value instanceof Blob) {
    const arrayBuffer = await value.arrayBuffer();
    project[key] = Buffer.from(arrayBuffer);
} else {
    project[key] = value;
}

如果需要更严谨的判断,可以同时检查是否包含name属性(模拟File的行为):

if (value instanceof Blob && 'name' in value) {
    // 处理文件
}

2. 优化前端FormData生成逻辑

你当前先通过new FormData($form)获取表单原生数据,再用projectForm的字段覆盖,这可能导致重复或错误覆盖文件:

  • 如果表单中的文件输入已经被FormData捕获,再次用formData.append/set可能导致字段重复或替换错误
  • 确保projectForm中的文件确实是File对象(受控组件中正确处理文件上传的onChange事件,比如将e.target.files[0]存入状态)

建议直接使用表单原生的FormData,而非手动覆盖:

// 移除手动遍历projectForm的代码,直接使用原生FormData
let formData = new FormData($form);

// 仅在需要补充额外字段时再append,不要覆盖已有表单字段

如果必须使用projectForm的状态来生成FormData,确保所有文件字段都是正确的File对象,并且不要重复处理相同字段。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 10:09:59