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

Supabase存储新上传图片无法立即显示,报400错误

Supabase Storage 上传图片后立即访问返回400错误的问题

向Supabase Storage上传图片并更新数据库中的图片URL后,立即尝试显示图片时会收到GET请求的400状态码错误。但单独访问这些URL、刷新页面后都能正常加载图片,且之前上传的图片显示完全正常,仅新上传的图片会出现此问题。

相关代码

表单提交逻辑

const handleFormSubmit = async (
    values: Artist,
    setSubmitting: SetSubmitting
) => {
    setSubmitting(true)

    // Filter images to don't upload images that are going to be deleted and vice versa
    const {
        itemsToUploadClone: imagesToUploadClone,
        itemsToDeleteClone: imagesToDeleteClone,
    } = filterItems(imagesToUpload, imagesToDelete)

    try {
        // Perform image upload and deletion in parallel
        await Promise.all([
            imagesToUploadClone.length > 0
                ? uploadImages(imagesToUploadClone, values.imgList)
                : Promise.resolve(),
            imagesToDeleteClone.length > 0
                ? deleteArtistImages(imagesToDeleteClone)
                : Promise.resolve(),
        ])

        const success = await apiUpdateArtist(values)

        if (success) {
            navigate('/artists/details/' + values.id)
            popNotification(t('artists.artistUpdated'))
        }
    } catch (error) {
        console.error(
            'Error in processing images or updating artist: ',
            error
        )
    } finally {
        setSubmitting(false)
    }
}

图片上传与处理逻辑

const uploadImages = async (
    imagesToUpload: Image[],
    formImages: Image[]
) => {
    await Promise.all(
        imagesToUpload.map(async (imageToUpload) => {
            try {
                const formImage = formImages.find(
                    (img) => img.id === imageToUpload.id
                ) as Image

                const rawFile = await getFileFromBlobUrl(
                    imageToUpload.rawFilePath,
                    imageToUpload.fileName
                )

                // resize image to 3 different sizes and upload them to supabase storage

                const resizeOptions: ResizeOption[] = [
                    {
                        maxWidth: 144,
                        maxHeight: 144,
                        format: 'WEBP',
                        quality: 75,
                        minWidth: 144,
                        minHeight: 144,
                    },
                    {
                        maxWidth: 760,
                        maxHeight: 760,
                        format: 'JPEG',
                        quality: 90,
                        minWidth: 480,
                        minHeight: 480,
                    },
                    {
                        maxWidth: 2000,
                        maxHeight: 2000,
                        format: 'JPEG',
                        quality: 90,
                    },
                ]

                try {
                    const resizePromises = resizeFile(
                        rawFile,
                        resizeOptions
                    )
                    let resizedImages = await Promise.all(resizePromises)
                    resizedImages = [...resizedImages, rawFile]

                    const sizes = [
                        'small',
                        'medium',
                        'large',
                        'raw',
                    ] as const

                    resizedImages.forEach(async (resizedImage, index) => {
                        const filePath = `/img/artist/${artistData.id}/${
                            sizes[index]
                        }/${imageToUpload.id}.${resizedImage.type
                            .split('/')[1]
                            .toLowerCase()}`

                        await supabase.storage.from('general').upload(filePath, resizedImage)
                    })

                    const imageBaseUrl = `${
                        import.meta.env.VITE_SUPABASE_STORAGE_URL
                    }/img/artist/${artistData.id}`

                    formImage.smallFilePath = `${imageBaseUrl}/small/${
                        imageToUpload.id
                    }.${resizedImages[0].type.split('/')[1]}`

                    formImage.mediumFilePath = `${imageBaseUrl}/medium/${
                        imageToUpload.id
                    }.${resizedImages[1].type.split('/')[1]}`

                    formImage.largeFilePath = `${imageBaseUrl}/large/${
                        imageToUpload.id
                    }.${resizedImages[2].type.split('/')[1]}`

                    formImage.rawFilePath = `${imageBaseUrl}/raw/${
                        imageToUpload.id
                    }.${resizedImages[3].type.split('/')[1]}`
                } catch (error) {
                    console.error('Error resizing images:', error)
                }
            } catch (error) {
                console.error('Error uploading image: ', error)
            }
        })
    )
}

图片展示逻辑

{imgList.map((img) => (
                <SortableItem key={img.id} id={img.id}>
                    <div
                        key={img.id}
                        className="group relative rounded border p-2 flex justify-center touch-pan-x aspect-square"
                    >
                        <img
                            className="rounded object-contain"
                            src={img.smallFilePath}
                            alt={img.fileName}
                        />
                        <div className="absolute inset-2 bg-gray-900/[.7] group-hover:flex hidden text-xl items-center justify-center">
                            <span
                                className="text-gray-100 hover:text-gray-300 cursor-pointer p-1.5"
                                onClick={() => onViewOpen(img)}
                            >
                                <HiEye />
                            </span>
                            <span
                                className="text-gray-100 hover:text-gray-300 cursor-pointer p-1.5"
                                onClick={() => onDeleteConfirmation(img)}
                            >
                                <HiTrash />
                            </span>
                        </div>
                    </div>
                </SortableItem>
            ))}

排查尝试

  • 给图片显示添加1秒延迟后,图片可正常加载
  • 首次报错后刷新页面,图片也能正常加载
  • 尝试过轮询检查图片可用性,但认为这不是最优解

需求:希望找到无需临时方案(延迟/轮询)就能让图片上传后立即正常显示的解决办法。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 09:25:01