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

基于Remix和TypeScript的Shopify应用图片上传问题求助

Shopify Remix+TypeScript图片上传处理错误修复方案

问题描述

使用Remix+TypeScript开发Shopify自定义应用的图片上传功能,前端可触发上传操作,但后台显示「1.png Processing error」,上传仅完成第一步,处理和就绪阶段失败。

核心问题分析

你的代码只完成了获取Shopify上传预签名地址这一步,但没有把实际的文件内容上传到该地址,导致Shopify无法找到文件进行后续处理,最终触发Processing error。具体问题点:

  • 前端仅提交了文件名、类型、大小,未传递实际文件内容
  • 后端拿到预签名地址后,没有执行文件上传到该地址的操作
  • 直接用空的resourceUrl调用fileCreate,自然无法完成处理

修复步骤及代码修改

1. 前端修改:用FormData传递实际文件

修改generateProduct函数,通过FormData提交文件,而不是普通键值对:

const generateProduct = () => {
  if (!files[0]) return;
  const formData = new FormData();
  formData.append("file", files[0]);
  submit(formData, { replace: true, method: "POST" });
};

2. 后端Action修改:解析FormData并上传文件到预签名地址

更新action函数,完成文件上传到staged target的步骤:

export const action = async ({ request }: ActionFunctionArgs) => {
  const { admin } = await authenticate.admin(request);
  // 解析FormData获取实际文件
  const formData = await request.formData();
  const file = formData.get("file") as File;
  if (!file) {
    return json({ error: "No file provided" }, { status: 400 });
  }

  // 准备staged上传参数
  const preparedFiles = [
    {
      filename: file.name,
      mimeType: file.type,
      resource: file.type.includes("image") ? "IMAGE" : "FILE",
      fileSize: file.size.toString(),
      httpMethod: "POST",
    },
  ];

  // 获取预签名上传地址
  const uploadFileResponse = await admin.graphql(
    `#graphql
    mutation stagedUploadsCreate($input: [StagedUploadInput!]!) {
      stagedUploadsCreate(input: $input) {
        stagedTargets {
          resourceUrl
          url
          parameters {
            name
            value
          }
        }
        userErrors {
          field
          message
        }
      }
    }
  `,
    { variables: { input: preparedFiles } },
  );

  const uploadFileJson = await uploadFileResponse.json();
  const stagedTarget = uploadFileJson.data.stagedUploadsCreate.stagedTargets[0];
  
  // 检查是否有用户错误
  const userErrors = uploadFileJson.data.stagedUploadsCreate.userErrors;
  if (userErrors.length > 0) {
    return json({ error: userErrors }, { status: 400 });
  }

  // 构建上传表单数据,包含预签名参数
  const uploadFormData = new FormData();
  stagedTarget.parameters.forEach((param: { name: string; value: string }) => {
    uploadFormData.append(param.name, param.value);
  });
  uploadFormData.append("file", file);

  // 上传文件到Shopify的预签名地址
  await fetch(stagedTarget.url, {
    method: "POST",
    body: uploadFormData,
  });

  // 调用fileCreate创建文件记录
  const fileCreateResponse = await admin.graphql(
    `#graphql
    mutation fileCreate($files: [FileCreateInput!]!) {
      fileCreate(files: $files) {
        files {
          alt
          createdAt
          fileStatus
          fileErrors {
            code
            details
            message
          }
          preview {
            image {
              url
            }
            status
            __typename
          }
          ... on GenericFile {
            id
          }
          ... on Video {
            id
          }
        }
        userErrors {
          code
          field
          message
        }
      }
    }`,
    {
      variables: {
        files: [
          {
            alt: "Image",
            contentType: "IMAGE",
            originalSource: stagedTarget.resourceUrl,
          },
        ],
      },
    },
  );

  const fileCreateJson = await fileCreateResponse.json();
  return json({
    stagedUpload: uploadFileJson,
    fileCreate: fileCreateJson,
    resourceUrl: stagedTarget.resourceUrl,
  });
};

3. 额外优化:添加错误处理

在前端添加对action返回错误的处理,替换原有的useEffect:

useEffect(() => {
  if (actionData) {
    if (actionData.error) {
      shopify.toast.show(`上传失败: ${JSON.stringify(actionData.error)}`);
    } else {
      shopify.toast.show("图片上传成功");
    }
  }
}, [actionData]);

关键说明

  • Shopify的staged上传流程分为三步:先获取预签名地址,再把文件上传到该地址,最后调用fileCreate关联资源
  • 必须传递实际文件内容到预签名地址,否则Shopify无法处理文件
  • 要注意FormData的正确使用,前端和后端都要对应解析

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 05:45:54