升级NextJS 13后使用createObjectURL无法创建图片文件
问题分析与解决方案
核心问题
你遇到的问题根源在于二进制数据通过JSON传输时被损坏:
- 服务器端用
res.json()返回arrayBuffer时,Node会把二进制数据转换成普通JavaScript数组(每个字节对应数组元素),丢失了原始二进制的结构。 - 客户端用
res.json()接收后得到的是这个数组,而非原始ArrayBuffer,转成Blob后数据已损坏,导致URL.createObjectURL生成的URL无法正确解析图片。
旧版本环境能工作是巧合(比如隐式的转换兼容),但这种传输方式本身不符合规范,升级后NextJS/Node的处理逻辑严格化,问题就暴露了。
修复代码
1. 修改API路由(pages/api/getImageData.js)
直接返回二进制数据流,避免JSON转换:
import axios from "axios"; export default async (req, res) => { // 改为JSON格式传参,避免body解析问题 const { url: imageUrlStr } = req.body; const imageUrl = new URL(imageUrlStr); const imageData = await axios.get(imageUrl.toString(), { responseType: 'arraybuffer', }); // 从响应头获取真实图片类型,替代模糊的image/* const contentType = imageData.headers['content-type'] || 'image/jpeg'; res.setHeader('Content-Type', contentType); // 直接发送二进制数据,不转JSON res.status(200).send(imageData.data); }
2. 修改客户端代码(pages/index.js)
直接获取原始ArrayBuffer,再生成Blob:
await fetch("/api/getImageData", { method: "POST", headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ url: fileSrc }) // 改为JSON格式传参 }) .then(res => { // 获取响应头里的图片类型 const contentType = res.headers.get('content-type') || 'image/jpeg'; return Promise.all([res.arrayBuffer(), contentType]); }) .then(([bufferData, contentType]) => new Blob([bufferData], { type: contentType })) .then(blob => { console.log(blob) try { const url = URL.createObjectURL(blob) console.log("Image created: " + url) // 这里可以用该URL展示图片或保存文件 } catch(e) { console.log(e) } })
额外说明
- 为什么用
res.send()而非res.json():res.send()会直接传输原始二进制数据,不会做JSON序列化,保证数据完整性。 - 规范传参方式:把图片URL放在JSON对象里传输,避免NextJS 13中API路由对raw body解析的潜在问题。
内容的提问来源于stack exchange,提问作者daviddev95
相关产品推荐
相关产品推荐

