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

使用Uppy+Supabase实现断点续传时遇对象名非法字符错误

使用Uppy + Supabase 上传文件时提示“对象名称包含无效字符”

问题详情

我在Web应用中尝试用Uppy结合Supabase实现文件上传功能,跟着教程写了代码,但上传时一直报错:

"error": "Invalid Input",   "message": "The object name contains invalid characters"

试过教程代码,也试过Supabase官方提供的Uppy示例代码,结果完全一样。已经测试过test.png、image.jpeg这类简单文件名的文件,还是无法上传。

我的代码

"use client";
import React, { useEffect, useState } from "react";
import Uppy from "@uppy/core";

import { Dashboard } from "@uppy/react";

import Tus from "@uppy/tus";
import "@uppy/core/dist/style.min.css";
import "@uppy/dashboard/dist/style.min.css";
import { createBrowserClient } from "@supabase/ssr";

function ImagesDragzone() {
  const [images, setImages] = useState<any[]>([]);
  const [loading, setIsLoading] = useState(false);
  const [error, setError] = useState<any>(null);

  const SUPABASE_ANON_KEY = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
  const SUPABASE_PROJECT_ID = "vopvzwbjhdsvhnwvluwb";
  const STORAGE_BUCKET = "library";
  const BEARER_TOKEN = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;

  const supabaseStorageURL = `https://${SUPABASE_PROJECT_ID}.supabase.co/storage/v1/object/public/`;

  const supabase = createBrowserClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
  );

  var uppy = new Uppy().use(Tus, {
    endpoint: supabaseStorageURL,
    headers: {
      authorization: `Bearer ${BEARER_TOKEN}`,
      apikey: SUPABASE_ANON_KEY as string,
    },
    uploadDataDuringCreation: true,
    chunkSize: 6 * 1024 * 1024,
    allowedMetaFields: [
      "bucketName",
      "objectName",
      "contentType",
      "cacheControl",
    ],
  });

  useEffect(() => {
    getBucket();

    uppy.on("file-added", (file) => {
      const supabaseMetadata = {
        bucketName: STORAGE_BUCKET,
        objectName: file.name,
        contentType: file.type,
      };

      file.meta = {
        ...file.meta,
        ...supabaseMetadata,
      };

      console.log("file added", file);
    });

    uppy.on("complete", (result) => {
      console.log(
        "Upload complete! We’ve uploaded these files:",
        result.successful
      );
    });
  }, []);

  async function getBucket() {
    setIsLoading(true);
    const { data, error } = await supabase.storage.from("library").list();

    // console.log(data);
    // console.log(error);

    if (error) {
      setError(error);
    } else {
      setImages(data);
    }

    setIsLoading(false);
  }
  return (
    <div>
      <h1>Image Showcase</h1>
      {error && <div>errror</div>}

      <div>
        <Dashboard uppy={uppy} showProgressDetails={true} />
      </div>

      {loading && <div>Loading...</div>}
      {!loading && images.length > 0 && (
        <>
          <h1>My images</h1>
          <ul>
            {images.map((image) => (
              <li key={image.name}>{/* uploaded image here */}</li>
            ))}
          </ul>
        </>
      )}
    </div>
  );
}

export default ImagesDragzone;

解决方案

核心问题

你的Tus上传端点完全写错了。Supabase的Tus断点续传上传有专门的接口地址,不是你当前使用的对象访问URL。你用的object/public/路径是用来读取已上传文件的,不是上传接口,这才导致了“无效字符”的错误提示(实际上是接口解析请求时出错)。

具体修改步骤

  1. 修正上传端点
    把supabaseStorageURL改成Supabase官方指定的Tus上传地址:
const supabaseStorageURL = `https://${SUPABASE_PROJECT_ID}.supabase.co/storage/v1/upload/resumable`;
  1. 添加Uppy实例清理逻辑
    组件卸载时关闭Uppy实例,避免内存泄漏:
useEffect(() => {
  // ... 原有代码

  return () => {
    uppy.close();
  };
}, []);
  1. 文件名安全处理(可选但推荐)
    即使你用了简单文件名,也可以添加一次字符过滤,避免潜在的特殊字符问题:
uppy.on("file-added", (file) => {
  // 过滤文件名中的非法字符,只保留字母、数字、._-
  const sanitizedFileName = file.name.replace(/[^a-zA-Z0-9._-]/g, '_');
  const supabaseMetadata = {
    bucketName: STORAGE_BUCKET,
    objectName: sanitizedFileName,
    contentType: file.type,
  };

  file.meta = {
    ...file.meta,
    ...supabaseMetadata,
  };
});
  1. 上传完成后刷新文件列表
    在complete事件里调用getBucket(),让上传的文件立刻显示出来:
uppy.on("complete", (result) => {
  console.log("Upload complete! We’ve uploaded these files:", result.successful);
  getBucket();
});

修改后的关键代码片段

// 修正后的上传端点
const supabaseStorageURL = `https://${SUPABASE_PROJECT_ID}.supabase.co/storage/v1/upload/resumable`;

var uppy = new Uppy().use(Tus, {
  endpoint: supabaseStorageURL,
  headers: {
    authorization: `Bearer ${BEARER_TOKEN}`,
    apikey: SUPABASE_ANON_KEY as string,
  },
  uploadDataDuringCreation: true,
  chunkSize: 6 * 1024 * 1024,
  allowedMetaFields: [
    "bucketName",
    "objectName",
    "contentType",
    "cacheControl",
  ],
});

useEffect(() => {
  getBucket();

  uppy.on("file-added", (file) => {
    const sanitizedFileName = file.name.replace(/[^a-zA-Z0-9._-]/g, '_');
    const supabaseMetadata = {
      bucketName: STORAGE_BUCKET,
      objectName: sanitizedFileName,
      contentType: file.type,
    };

    file.meta = {
      ...file.meta,
      ...supabaseMetadata,
    };
  });

  uppy.on("complete", (result) => {
    console.log("Upload complete! We’ve uploaded these files:", result.successful);
    getBucket();
  });

  return () => {
    uppy.close();
  };
}, []);

完成以上修改后,就能正常上传文件了。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 07:43:14