Jas*_*ert 15 javascript node.js asp.net-web-api asp.net-core next.js
我正在尝试在 Next.js 应用程序中裁剪图像,将其发送到应用程序中的 API 路由,最后发送到应用程序外部的 API 端点。如果我绕过 API 路由,它可以正常工作,但在通过它时就不行了。图像数据不再正确且无法处理。
客户端 (Next.js) --> API 路由 (Next.js) --> API 端点(外部)
客户端 (Next.js) -fetch使用FormDataviaPOST
async function handleSave(image: Blob) {
const file = new File([image], 'avatar.png', { type: 'image/png' })
const data = new FormData()
data.append('imageFile', file)
const response = await fetch(`/api/users/${userId}/media/avatar`,
{
body: data,
method: 'POST',
}
)
// const response = await fetch (`https://localhost:1337/user/${userId}/media/avatar`, {
// method: 'POST',
// headers: {
// "Authorization": `Bearer <JWT token>`,
// },
// body: data
// })
if (response.ok) {
// handle
}
}
Run Code Online (Sandbox Code Playgroud)
注释掉的 fetch 是我测试直接调用外部 API 端点的地方,这工作正常。
API 路由 (Next.js) - 从客户端获取请求并将其转发到外部 API 端点。
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
await cors(req, res)
const { userId } = req.query;
const { accessToken } = await getToken({ req, secret });
const response = await fetch(`${process.env.API_HOST}/user/${userId}/media/avatar`, {
method: 'POST',
headers: {
"Authorization": `Bearer ${accessToken}`,
"Content-Type": req.headers["content-type"]
},
body: req.body
})
try {
const json = await response.json();
console.log(json)
}
finally { }
res.end()
}
Run Code Online (Sandbox Code Playgroud)
API 端点(外部)
multipart/form-dataimageFile并映射到IFormFile一旦请求通过 API 路由传递并发送到外部 API,图像流就不再有效。我可以看到该IFormFile对象已选择imageFile“确定”并获取了相关数据。
当我绕过 Next.js API 路由时,上传工作正常,并且我注意到IFormFile对象长度要小得多。
通过 Next.js API 路由非常重要,因为它负责将访问令牌传递给外部 API,并且无意公开该 API。
我已经查看了在 next.js 中创建上传文件 api,但我不确定如何/是否formidable适合这种情况?
经过大量挖掘并尝试了许多不同的方法后,我终于找到了一种有效的方法。
multipart/form-data文件。formidable读取文件,首先保存到磁盘,然后fs读取该文件,最后在FormData.import Cors from 'cors'
import initMiddleware from '../../../../../lib/initMiddleware'
import { NextApiRequest, NextApiResponse } from 'next'
import { getToken } from 'next-auth/jwt'
import fetch from "node-fetch";
import FormData from 'form-data'
import { IncomingForm } from 'formidable'
import { promises as fs } from 'fs';
export const config = {
api: {
bodyParser: false,
},
}
const cors = initMiddleware(
Cors({
methods: ['POST']
})
)
const secret = process.env.NEXTAUTH_SECRET;
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
await cors(req, res)
const { userId } = req.query;
const { accessToken } = await getToken({ req, secret });
const fData = await new Promise<{ fields: any, files: any }>((resolve, reject) => {
const form = new IncomingForm({
multiples: false
})
form.parse(req, (err, fields, files) => {
if (err) return reject(err)
resolve({ fields, files })
})
});
const imageFile = fData.files.imageFile
const tempImagePath = imageFile?.filepath
try {
const image = await fs.readFile(tempImagePath)
const data = new FormData()
data.append('imageFile', image, { filename: 'avatar.png' })
const response = await fetch(`${process.env.API_HOST}/user/${userId}/media/avatar`, {
method: 'POST',
headers: {
"Authorization": `Bearer ${accessToken}`,
"Content-Type": `multipart/form-data; boundary=${data.getBoundary()}`
},
body: data
})
if (!response.ok) {
}
res.status(response.status);
}
catch (error) {
}
finally {
if (tempImagePath) {
await fs.rm(tempImagePath)
}
}
res.end()
}
Run Code Online (Sandbox Code Playgroud)
小智 5
我遇到了同样的问题,最后我找到了非常优雅的方法来解决它。
解决方案来源:https://github.com/vercel/next.js/discussions/15727#discussioncomment-1094126
以防万一,我从源代码复制代码:
文件上传组件
const uploadFile = (file : File) => {
let url = "http://localhost:3000/api/upload";
let formData = new FormData();
formData.set("testFile", file)
fetch(url, {
method: "POST",
body: formData,
}).then(r => {
console.log(r);
})
}
Run Code Online (Sandbox Code Playgroud)
/api/upload.ts:
import {NextApiRequest, NextApiResponse} from "next";
import httpProxyMiddleware from "next-http-proxy-middleware";
// For preventing header corruption, specifically Content-Length header
export const config = {
api: {
bodyParser: false,
},
}
export default (req: NextApiRequest, res: NextApiResponse) => {
httpProxyMiddleware(req, res, {
target: 'http://localhost:21942'
})
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
22478 次 |
| 最近记录: |