如何通过NextJS API代理将图片上传至Azure Blob Storage
问题原因
你的代码存在两个核心问题导致图片上传后变成乱码:
- 前端手动设置了
multipart/form-data请求头,丢失了浏览器自动生成的boundary参数,导致后端无法正确解析文件二进制数据。 - NextJS API路由默认不会解析
multipart/form-data格式的请求,req.body会被处理成字符串而非原始二进制流,直接传给Azure Blob时自然会变成乱码。
解决方案
前端代码修改
移除手动设置的Content-type请求头,FormData提交时浏览器会自动生成包含boundary的正确请求头:
const [image, setImage] = useState({ preview: '', raw: '' }) const handleImageChange = (e) => { setImage({ preview: URL.createObjectURL(e.target.files[0]), raw: e.target.files[0] }) } // 上传逻辑 const uploadImage = async () => { if (!image.raw) return const picFile = new FormData() picFile.append("image", image.raw) const picOptions = { method: 'POST', // 移除手动设置的Content-type,浏览器会自动处理 body: picFile, } const picResponse = await fetch(profilePicEndpoint, picOptions) const result = await picResponse.json() console.log(result) } return ( <> <input accept=".png, .jpg, .jpeg" type="file" id="image-upload" style={{ display: 'none' }} onChange={handleImageChange} /> <button onClick={uploadImage}>上传头像</button> </> )
后端NextJS API路由修改
需要使用formidable库解析multipart/form-data请求,获取文件的二进制buffer后再上传到Azure Blob:
- 安装依赖:
npm install formidable
- 修改API路由代码:
import formidable from 'formidable' import fs from 'fs/promises' // 禁用NextJS默认的bodyParser,因为要手动解析multipart/form-data export const config = { api: { bodyParser: false, }, } export default async function handler(req, res) { if (req.method !== 'POST') { return res.status(405).json({ message: '仅支持POST请求' }) } // 解析FormData const form = formidable({}) const [fields, files] = await form.parse(req) // 获取上传的文件对象 const uploadedFile = files.image?.[0] if (!uploadedFile) { return res.status(400).json({ message: '未上传文件' }) } // 动态生成Blob文件名(避免覆盖),使用原始文件名 const blobFileName = uploadedFile.originalFilename const blobEndpoint = `https://STORAGEACCOUNT.blob.core.windows.net/MyContainerhere/${blobFileName}?BunchofCredentialsHere` // 读取文件的二进制buffer const fileBuffer = await fs.readFile(uploadedFile.filepath) // 上传到Azure Blob const blobOptions = { method: 'PUT', headers: { 'x-ms-blob-type': 'BlockBlob', // 设置正确的Content-Type,用文件原始的MIME类型 'Content-Type': uploadedFile.mimetype }, body: fileBuffer, } const blobResponse = await fetch(blobEndpoint, blobOptions) if (!blobResponse.ok) { return res.status(500).json({ message: '上传到Azure失败' }) } res.status(200).json({ message: '上传成功,更新将在24小时内生效', blobUrl: blobEndpoint.split('?')[0] // 返回不带SAS的Blob地址 }) }
关键说明
- 禁用NextJS默认的
bodyParser是必须的,否则formidable无法正确解析请求。 - 必须设置
Content-Type为文件原始的MIME类型,确保Azure Blob存储正确识别文件格式。 - 动态设置Blob文件名,避免每次上传覆盖同一个文件。
内容的提问来源于stack exchange,提问作者Chance
相关产品推荐
相关产品推荐

