我有一个
File
类型的对象,它由 Node.js 后端处理。
export default function handler(req: NextRequest, res: NextResponse<Object>) {
console.log("METHOD: ", req.method)
if (req.method == "POST") {
const form = new Formidable.IncomingForm()
form.parse(req, (error: any, fields: any, files: any) => {
console.log(fields)
console.log(files.image)
await Sharp(Buffer.from(files.image))
.toFormat("webp")
.toFile("save.webp")
})
res.status(200).send({ message: "Success" })
} else {
res.status(404).send({ message: "POST only supported" })
}
}
files.image
的类型为File
,当我尝试将其传递到Buffer.from()
时,我会收到错误
The first argument must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object. Received an instance of File
我尝试传入
await Sharp(Buffer.from(files.image, 'base64'))
但出现同样的错误。有什么办法可以把 files.image
变成 Buffer Sharp 可以理解的吗?
更新:我找到了一种通过使用以下方法来实现我的目标的方法:
if (req.method == "POST") {
const form = new Formidable.IncomingForm()
form.parse(req, (error: any, fields: any, files: any) => {
// Pass in the temp file location where the incoming form stores the request
ConvertToWebP(files.image.path)
})
res.status(200).send({ message: "Success" })
} else {
res.status(404).send({ message: "POST only supported" })
}
}
经过几个小时的不同方法后,我通过查看
File
对象发现了这一点:
{
image: File {
_events: [Object: null prototype] {},
_eventsCount: 0,
_maxListeners: undefined,
size: 481,
path: 'C:\\XXX\\XXX\\AppData\\Local\\Temp\\upload_XXX',
name: 'eagle.png',
type: 'image/png',
hash: null,
...
注意:我想保持这个问题的开放性,因为这个解决方法可能有效,但我仍然想了解为什么我不能传入 Buffer 对象。
File
接口 filepath
属性将上传的文件内容读取到 Buffer 中。
...
import * as fs from 'fs';
...
const buf = await fs.promises.readFile(files.image.filepath);
await Sharp(buf);
...
...
如果有人遇到这个问题,尝试将图像文件从客户端上传到服务器,并使用 Sharp 处理它们,我是这样做的:
在客户端,我发送带有表单数据的 POST 请求:
const formData = new FormData()
for (const file of files) {
formData.append("files", file, file.name)
}
const r = await fetch(url, {
method: "POST",
body: formData,
})
在服务器上,我们需要1)使用中间件(例如Express或单独的中间件文件 - 我使用后者)将多部分内容类型的表单数据处理为FileStream(它不会是文件对象),2)将FileStream处理为数据块,3)将数据块数组与缓冲区合并(参见this答案)并将它们附加到主体。我用过Busboy:
const busboy = require('busboy')
const parseMultipartBody = async (req, res, next) => {
const bb = busboy({ headers: req.headers })
req.body.filesAsBuffer = []
// every file here will be FileStream, not File Object
bb.on('file', (name, file, info) => {
const data = []
let fileAsBuffer
file.on('data', (chunk) => {
data.push(chunk)
}).on('close', async () => {
// merge data chunks with buffer and attach them to body
fileAsBuffer = await Buffer.concat(data)
req.body.filesAsBuffer.push(fileAsBuffer)
})
})
bb.on('close', () => {
next()
})
req.pipe(bb)
}
在路线上我们可以使用Sharp进行任何我们需要的操作:
const sharp = require('sharp')
export const POST = async (req, res) => {
const { body } = req
const { filesAsBuffer } = body
for (const fileAsBuffer of filesAsBuffer) {
const metadata = await sharp(fileAsBuffer).metadata()
console.log(1, metadata)
}
...
}