Next.js 13应用上传Azure Blob Storage失败及错误排查
在Next.js 13中上传文件到Azure Blob Storage的问题
我正尝试在Next.js 13应用中上传文件至Azure Blob Storage,认为文件对象不符合Blob或Buffer要求,尝试转换后仍未解决问题。当前无法完成文件上传,报错信息如下:
Invalid file format:
⨯ RangeError [ERR_HTTP_INVALID_STATUS_CODE]: Invalid status code: 0
前端组件代码
"use client"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { useToast } from "@/components/ui/use-toast"; import { DialogClose } from "@radix-ui/react-dialog"; import { useState } from "react"; import { ButtonLoading } from "../LoadingButton"; import axios from 'axios'; export default function UploadData() { const [file, setFile] = useState<File | null>(null); const [isLoading, setIsLoading] = useState(false); const { toast } = useToast(); const handleUrlInput = (event: React.ChangeEvent<HTMLInputElement>) => { const selectedFile = event.target.files?.[0] if (selectedFile) { setFile(selectedFile); } }; const handleSubmit = async () => { const formData = new FormData(); if (file) { formData.append('file', file); } console.log(formData) const response = axios.post('/api/ingest', formData, { headers: { 'Content-Type': 'multipart/form-data', }, }) // Handle the response if ((await response).status === 200) { // File uploaded successfully console.log('File uploaded successfully!'); } else { // Something went wrong console.log('Error uploading file:', response); } } return ( <Dialog> <DialogTrigger asChild> {isLoading ? <ButtonLoading /> : <Button>Upload</Button>} </DialogTrigger> <DialogContent className="sm:max-w-[425px]"> <DialogHeader> <DialogTitle>Edit profile</DialogTitle> <DialogDescription> Enter URL which you want to provide as input for retrieving information. </DialogDescription> </DialogHeader> <div className="grid gap-4 py-4"> <div className="grid grid-cols-4 items-center gap-4"> <Label htmlFor="name">URL</Label> <Input id="name" type="file" onChange={handleUrlInput} className="col-span-full" /> </div> </div> <DialogFooter> <DialogClose asChild> <Button type="submit" onClick={handleSubmit} > Submit </Button> </DialogClose> </DialogFooter> </DialogContent> </Dialog> ); }
API路由代码
export async function POST(request: Request, res: Response) { try { // const file = (await request.formData())?.get("file") as Blob; const formData = await request.formData(); const filePart = formData.get("file"); console.log("filePart", typeof filePart); if (filePart instanceof Blob) { const fileName = filePart.name; const buffer = Buffer.from(await filePart.arrayBuffer()); console.log("File Name:", fileName); console.log("Buffer:", buffer); const blobClient = containerClient.getBlockBlobClient(fileName); await blobClient.uploadData(buffer); return NextResponse.json(res); } else { console.log("Invalid file format"); return NextResponse.error(); } } catch (e) { console.log(e); return NextResponse.error(); } }
问题修复方案
1. 修复API路由的响应错误
- Next.js 13 App Router的API路由无需
res参数,NextResponse.json(res)是错误用法,需返回自定义响应体与合法状态码 NextResponse.error()会默认返回状态码0(无效值),需手动指定错误状态码
修改后的API路由:
import { NextResponse } from 'next/server'; // 确保containerClient已正确初始化并引入 export async function POST(request: Request) { try { const formData = await request.formData(); const filePart = formData.get("file"); if (filePart instanceof Blob) { // 兼容非File类型的Blob,设置默认文件名 const fileName = filePart instanceof File ? filePart.name : "unknown-file"; const buffer = Buffer.from(await filePart.arrayBuffer()); const blobClient = containerClient.getBlockBlobClient(fileName); await blobClient.uploadData(buffer); return NextResponse.json({ success: true, message: "文件上传成功" }, { status: 200 }); } else { console.log("Invalid file format"); return NextResponse.json({ error: "无效的文件格式" }, { status: 400 }); } } catch (e) { console.error("上传失败:", e); return NextResponse.json({ error: "文件上传失败" }, { status: 500 }); } }
2. 优化前端请求逻辑
- 手动设置
Content-Type: multipart/form-data会丢失boundary信息,导致后端无法解析FormData,需删除该配置 - 处理loading状态,避免重复提交
- 添加文件非空校验,提升用户体验
修改后的前端handleSubmit方法:
const handleSubmit = async () => { if (!file) { toast({ description: "请选择要上传的文件" }); return; } setIsLoading(true); try { const formData = new FormData(); formData.append('file', file); // 移除手动设置的Content-Type,axios会自动处理 const response = await axios.post('/api/ingest', formData); if (response.status === 200) { console.log('File uploaded successfully!'); toast({ description: "文件上传成功" }); } } catch (error) { console.log('Error uploading file:', error); toast({ description: "文件上传失败,请重试" }); } finally { setIsLoading(false); } }
3. 补充说明
浏览器中通过FormData上传的文件是File类型(Blob的子类),filePart instanceof Blob判断是成立的,若仍触发格式错误,需检查:
containerClient是否已正确初始化- 前端是否确实选择了文件再提交
内容的提问来源于stack exchange,提问作者Bhavesh Kumar Sharma
相关产品推荐
相关产品推荐

