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

Next.js 13中Supabase存储桶PDF文件上传失败求助

解决Next.js 13中PDF文件上传至Supabase存储桶无响应的问题

核心问题分析

你遇到的PDF上传无响应问题,主要由以下几个关键问题导致:

  • 响应提前终止:res.json("OK")写在form.parse回调外部,而form.parse是异步操作,PDF文件体积通常更大,还没完成解析就返回了响应,直接中断了解析流程。
  • Supabase客户端未初始化:代码中仅导入了createClient但未创建实例,会导致后续上传逻辑报错(虽未在问题中体现,但属于必修复的潜在问题)。
  • 错误处理缺失:未捕获form.parse和Supabase上传的错误,导致问题无法定位。
  • Content-Type识别不准确:通过临时文件路径获取MIME类型,可能因临时文件无后缀导致识别错误,影响PDF文件处理。

修复后的完整代码

前端代码(优化版)

async function uploadFile(ev) {
  if (ev.target.files.length > 0) {
    const files = ev.target.files;
    const data = new FormData();
    for (const file of files) {
      data.append('file', file);
    }

    try {
      const response = await fetch('/api/upload/', {
        method: "POST",
        body: data
      });
      const result = await response.json();
      console.log('上传结果:', result);
    } catch (err) {
      console.error('上传失败:', err);
    }
  }
}
<label htmlFor="myfile" name="myfile" style={{ width: "24px", height: "24px" }}>
  <input type="file" id="myFile" onChange={uploadFile} accept="*"/>
</label>

后端pages/api/upload.js代码

import { createClient } from '@supabase/supabase-js'
import multiparty from 'multiparty';
import fs from 'fs'
import mime from 'mime-types'
import crypto from 'crypto'

// 初始化Supabase客户端(替换为你的环境变量)
const supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL,
  process.env.SUPABASE_SERVICE_ROLE_KEY
);

// 禁用Next.js默认的body解析,让multiparty处理表单数据
export const config = {
  api: {
    bodyParser: false,
  },
};

export default async function handler(req, res) {
  if (req.method !== 'POST') {
    return res.status(405).json({ error: '仅支持POST请求' });
  }

  const form = new multiparty.Form({
    encoding: 'binary', // 明确设置二进制编码,适配PDF等二进制文件
    maxFilesSize: 10 * 1024 * 1024, // 按需调整最大文件大小(示例为10MB)
  });

  console.log("进入handler函数");

  try {
    // 用Promise包装form.parse,避免回调嵌套并确保异步流程完成
    const [fields, files] = await new Promise((resolve, reject) => {
      form.parse(req, (err, fields, files) => {
        if (err) reject(err);
        else resolve([fields, files]);
      });
    });

    console.log('解析到的文件:', files);

    if (!files.file || files.file.length === 0) {
      return res.status(400).json({ error: '未上传文件' });
    }

    const file = files.file[0];
    // 从原始文件名提取扩展名
    const fileExtension = file.originalFilename.split('.').pop() || 'pdf';
    const fileName = `${crypto.randomUUID()}.${fileExtension}`;
    // 读取二进制文件内容
    const fileContent = fs.readFileSync(file.path);
    // 优先从原始文件名获取MIME类型,兜底为PDF类型
    const contentType = mime.lookup(file.originalFilename) || 'application/pdf';

    const { data, error } = await supabase.storage.from("mybucket")
      .upload(fileName, fileContent, { contentType });

    if (error) {
      console.error('Supabase上传错误:', error);
      return res.status(500).json({ error: '文件上传至存储桶失败' });
    }

    res.status(200).json({ message: '上传成功', data });
  } catch (err) {
    console.error('解析或上传错误:', err);
    res.status(500).json({ error: '文件处理失败', details: err.message });
  }
}

关键修复说明

  1. 禁用默认Body解析:添加export const config配置,禁止Next.js自动解析请求体,确保multiparty能正确处理表单数据。
  2. 异步化form.parse:用Promise包装解析逻辑,避免回调嵌套,同时保证所有异步操作完成后再返回响应。
  3. 明确二进制编码:设置encoding: 'binary',确保multiparty正确解析PDF这类二进制文件。
  4. 完善错误捕获:添加全局try/catch,捕获解析、上传等环节的异常,返回明确的错误信息便于调试。
  5. 准确获取Content-Type:通过原始文件名获取MIME类型,避免临时文件路径导致的识别错误。
  6. 响应时机修正:所有操作完成后才返回响应,确保PDF文件有足够时间完成解析和上传。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 10:55:17