在Next.js中使用Supabase Storage的客户端上传时,如何在服务端对文件进行校验?
我有一个使用应用路由的Next.js应用,针对画廊功能有两个独立的上传路径,但我意识到服务器端的安全检查被绕过了。
安全路径(Server Action)- 验证魔术字节并强制执行10MB限制:
// app/actions/upload-gallery-image.ts
"use server";
function detectImageType(bytes: Uint8Array): string | null {
if (bytes[0] === 0xFF && bytes[1] === 0xD8 && bytes[2] === 0xFF) return "image/jpeg";
if (bytes[0] === 0x89 && bytes[1] === 0x50) return "image/png";
// ...
}
export async function uploadGalleryImage(formData: FormData) {
const file = formData.get("file") as File;
if (file.size > 10 * 1024 * 1024) return { error: "10MB limit" };
const bytes = new Uint8Array(await file.arrayBuffer());
if (!detectImageType(bytes)) return { error: "Invalid file type" };
await supabase.storage.from("gallery").upload(path, file);
}
客户端组件实际使用的路径——直接上传到Supabase存储,绕过了上述所有检查:
// app/(dashboard)/gallery/GalleryPageClient.tsx
"use client";
async function handleUpload() {
for (const file of selectedFiles) {
if (file.size > 50 * 1024 * 1024) { // only client-side check, 50MB not 10MB
alert("too large");
continue;
}
// Uploads directly — no magic byte check, no server validation
const { error } = await supabase.storage
.from("gallery")
.upload(storagePath, file, { contentType: file.type });
}
}
客户端组件直接使用Supabase JS SDK(以anon密钥初始化),因此完全跳过了具有正确安全逻辑的服务器端Action。
我想要的:
- 所有上传都经过服务器端Action,以便始终强制执行魔术字节验证和文件大小限制
- 支持多文件上传并为每个文件提供一个进度指示
- 保持用户体验的响应性(上传时不冻结界面)
我考虑过的方案:
- 对每个文件循环调用服务器端Action,但FormData的每个键只能放一个文件,且服务器端Action不能返回上传进度
- 改用一个API路由 (/api/upload) ——但这样就会失去服务器端Action的简洁性
- 通过Supabase存储桶策略强制限制 ——但这只覆盖大小,不涵盖魔术字节
问题: 在Next.js App Router中,处理必须通过服务器端验证(魔术字节、文件类型)的多文件上传,同时保持客户端界面响应性的推荐模式是什么?我应该转向API路由,还是有办法让服务器端Action在这里工作?
环境:
- Next.js 15(App Router)
- @supabase/ssr 0.5.2
- @supabase/supabase-js 2.49.4
解决方案
看起来这是因为你在执行Supabase客户端函数,而不是服务器端的Action。
你可以切换使用服务器端Action,通过在客户端直接导入并执行服务器端Action来实现,然后在Supabase中添加特定规则以禁用客户端上传
如果你需要上传进度,你必须使用API路由,这是唯一可行的方案。你会失去简洁性,但如果你确实需要上传进度,这其实并不是你需要过于担心的问题
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。