[英]next.js file upload via api routes / formidable - not working
我花了很長時間讓文件上傳通過 api 路由工作。
在客戶端即時提交文件,如下所示:
onFormSubmit = (e) => {
e.preventDefault() // Stop form submit
this.fileUpload(this.state.file).then((response) => {
console.log('rD', response.data)
})
}
onFileChange = (e) => {
this.setState({ file: e.target.files[0] })
}
fileUpload = (file) => {
const url = '/api/mail/upload'
const formData = new FormData()
formData.append('file', file)
const config = {
headers: {
'X-CSRF-TOKEN': this.props.session.csrfToken
}
}
return axios.post(url, formData, config)
}
我對/api/mail/upload
的請求如下所示:
Request Headers:
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9,de-DE;q=0.8,de;q=0.7
Connection: keep-alive
Content-Length: 1331
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryBlNt6z8t4rGZT0x6
Cookie: abc123
Host: localhost:3000
Origin: http://localhost:3000
Referer: http://localhost:3000/new
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36
X-CSRF-TOKEN: abc123
Form Data:
file: (binary)
然后在路由(/api/mail/upload)中,我嘗試使用強大的來解析表單數據,最后對文件做一些事情。
我確保通過在 api 路由文件的底部包含以下內容來禁用內置的正文解析器:
export const config = {
api: {
bodyParser: false
}
}
^^ 那是正確的方法,對吧?
最后,在 api 路線中,我嘗試了很多不同的東西,但目前以下是我期望的工作,但它不是..
module.exports = async (req, res) => {
const form = new formidable.IncomingForm()
form.parse(req, (err, fields, files) => {
if (err) return reject(err)
console.log(fields, files)
res.status(200).json({ fields, files })
})
// if I console.log(form) here - I can see the request details, so it seems to be picking that up
}
這不會在服務器端或客戶端生成任何輸出,我希望console.log(fields, files)
在服務器端輸出文件名等。
有人知道我錯過了什么嗎?
您只需要禁用 Next.js 內置正文解析器: https ://nextjs.org/docs/api-routes/api-middlewares#custom-config
這是工作示例:
// Backend
import formidable from 'formidable';
export const config = {
api: {
bodyParser: false,
},
};
export default async (req, res) => {
const form = new formidable.IncomingForm();
form.uploadDir = "./";
form.keepExtensions = true;
form.parse(req, (err, fields, files) => {
console.log(err, fields, files);
});
};
https://gist.github.com/agmm/da47a027f3d73870020a5102388dd820
我相信,如果您在端點內部進行異步操作,那么 next.js 期望您返回一個承諾,例如
export default (req, res) => {
const promise = new Promise((resolve, reject) => {
const form = new formidable.IncomingForm();
form.parse(req, (err, fields, files) => {
if (err) reject(err);
resolve({fields, files});
})
})
return promise.then(({fields, files}) => {
res.status(200).json({ fields, files })
})
}
我 100% 確定您的問題是由混合 CommonJS 導出(即module.exports =
)和 ES6 模塊語法( export const config = ...
)引起的。
當您執行此操作時,NextJS 只會看到默認導出並且看不到您的配置聲明,因此會繼續解析正文。 反過來,這會導致req
在它被傳遞給時已經完成了formidable
。
除此之外,您的代碼中的一切看起來都正確。 只要改變
module.exports = async (req, res) => {
至
export default async (req, res) => {
你應該得到一個預期的行為。
你可以用一種簡單的方式來實現它,如下所述->
以簡單的方式從客戶端發送文件將是 ->
客戶端->
const file = e.target.files[0];
const formData = new FormData();
formData.append("file", file);
const { data } = await axios.post("/api/upload",formData)
在后端安裝 express-formidable
后端 api 將是 ->
import express from 'express';
import expressAsyncHandler from 'express-async-handler';
import formidable from 'express-formidable';
const router = express.Router();
export const config = {
api: {
bodyParser: false,
},
};
export default router.post('/upload',formidable() ,expressAsyncHandler(async (req, res) => {
const {file} = req.files;
console.log(file);
// here you can handle the incoming file to send it to cloud
}));
express-formidable 將處理所有傳入的流並通過將所有數據存儲到“數據”變量來為我們提供數據。 為了將其存儲到任何雲(aws s3,cloudinary),創建一個可讀流並將其附加到表單數據中,然后發送它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.