在同一 POST 请求 (Angular) 上使用 multer (NodeJS) + 其他表单数据上传文件
Uploading file with multer (NodeJS) + other form data on same POST request (Angular)
我正在 Angular 构建前端提交表单。
该表单具有普通文本输入字段和文件上传功能。
我 POST 我的 NodeJS API 的文本输入字段作为 JSON 对象 "contact",以及作为新 FormData 的文件:
// 'contact' defined above as a JSON object
// 'profilePic' set from event.target.files[0] in a listener function
const profilePicData = new FormData();
profilePicData.append('file', profilePic);
return this.http
.post<ContactResponseData>('API_URL_HERE',
{ contact, profilePicData } ...
然后从我的 API 中捕获它:
router.post("/", upload.single('file'),(req, res) => {
console.log("REQ: "+ req);
console.log("BODY: " + JSON.stringify(req.body));
console.log("FILE: " + req.file);
req.file 是 "undefined",即空,而我的 req.body 有一个 "profilePicData" 键值对,它是空的。我认为这是因为整个表单作为 JSON 而不是多部分表单数据提交。
但是我无法google任何关于如何将 JSON 和多部分作为一个 POST 请求发送到我的 API 的任何有用信息,以便 [=26] =] 和 req.file 选择正确的信息。我想了解这里发生的事情背后的理论和最佳实践是我所追求的。我是否应该有两个 POST 网址,一个用于 JSON,一个用于文件?或者我是否也应该将 JSON 作为多部分提交(在 Angular 中我该怎么做)?感谢任何帮助。
您必须通过向 FormData
的实例添加字段并将其作为有效负载发送,将所有内容作为多部分发送。
const form = new FormData();
form.append('file', profilePic);
form.append('contact', contact);
...
return this.http.post<ContactResponseData>('API_URL_HERE', form, ...)
我在 React 中使用了下面的方法
下面是我创建输入的方式
<form className={styles.root} noValidate autoComplete="off">
<input
name="avatar_image" // name of input field or fieldName simply
enctype="multipart/form-data"
type="file"
onChange={(event) => {
// console logging selected file from menu
console.log( event.target.files[0] ) // gives first file
// setState method with event.target.files[0] as argument
this.setState(prev => ({...prev, user_image: event.target.files[0]}))
}}
/>
</form>
以下是我向后端发出请求的方式
const formData = new FormData()
formData.append('user_name', this.state.user_name)
formData.append('phone_number', this.state.phone_number)
// now below avatar_image is the fieldName of the image, then comes the file to upload, and the file name in the end
formData.append('avatar_image', this.state.user_image, this.state.user_image.name)
axios.post(utils.baseUrl + '/avatar-uploads/avatar-image-upload', formData, {
onUploadProgress: progressEvent => {
console.log( 'upload progress: ' + Math.round((progressEvent.loaded / progressEvent.total)*100) + '%' )
}
})
.then(function (response) {
// further code
})
.catch(function (error) {
console.log(error);
});
下面是我如何使用 multer 处理 backned,包括处理 payload
const image_storage = multer.diskStorage({
destination: path.join(__dirname , '../../assets/images/uploads/avatar_image'),
filename: function(req, file, cb){
cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname))
}
});
// Init Upload
const user_avatar_image_upload = multer({
storage: image_storage,
limits:{fileSize: 2000000}, // 1 mb
fileFilter: function(req, file, cb){
checkFileTypeForUserAvatar(file, cb);
}
}).single('avatar_image'); // this is the fieldName that will be dealt
// Check File Type
function checkFileTypeForUserAvatar(file, cb){
// Allowed ext
let filetypes = /jpeg|jpg|png|gif/;
// Check ext
let extname = filetypes.test(path.extname(file.originalname).toLowerCase());
// Check mime
let mimetype = filetypes.test(file.mimetype);
if(mimetype && extname){
return cb(null,true);
} else {
cb('Error: jpeg, jpg, png, gif Images Only!');
}
}
// router.post('/protected-avatar-image-upload', passport.authenticate('jwt', { session: false }), (req, res, next) => {
router.post('/avatar-image-upload', (req, res, next) => {
console.log(req.body) // here the req.body will turn out {}
user_avatar_image_upload(req, res, (err) => {
if(err){
console.log(err)
} else {
if(req.file == undefined){
res.status(404).json({ success: false, msg: 'File is undefined!',file: `uploads/${req.file.filename}`})
} else {
console.log( req.body.user_name ) // here req.body.user_name and others will work
// further code
res.status(200).json({ success: true, msg: 'File Uploaded!',file: `uploads/${req.file.filename}`})
}
}
})
})
希望这有助于如何使用 multer 上传文件,并传递额外的有效负载,以便它也可以用于创建数据库条目或其他任何东西。
我正在 Angular 构建前端提交表单。 该表单具有普通文本输入字段和文件上传功能。 我 POST 我的 NodeJS API 的文本输入字段作为 JSON 对象 "contact",以及作为新 FormData 的文件:
// 'contact' defined above as a JSON object
// 'profilePic' set from event.target.files[0] in a listener function
const profilePicData = new FormData();
profilePicData.append('file', profilePic);
return this.http
.post<ContactResponseData>('API_URL_HERE',
{ contact, profilePicData } ...
然后从我的 API 中捕获它:
router.post("/", upload.single('file'),(req, res) => {
console.log("REQ: "+ req);
console.log("BODY: " + JSON.stringify(req.body));
console.log("FILE: " + req.file);
req.file 是 "undefined",即空,而我的 req.body 有一个 "profilePicData" 键值对,它是空的。我认为这是因为整个表单作为 JSON 而不是多部分表单数据提交。
但是我无法google任何关于如何将 JSON 和多部分作为一个 POST 请求发送到我的 API 的任何有用信息,以便 [=26] =] 和 req.file 选择正确的信息。我想了解这里发生的事情背后的理论和最佳实践是我所追求的。我是否应该有两个 POST 网址,一个用于 JSON,一个用于文件?或者我是否也应该将 JSON 作为多部分提交(在 Angular 中我该怎么做)?感谢任何帮助。
您必须通过向 FormData
的实例添加字段并将其作为有效负载发送,将所有内容作为多部分发送。
const form = new FormData();
form.append('file', profilePic);
form.append('contact', contact);
...
return this.http.post<ContactResponseData>('API_URL_HERE', form, ...)
我在 React 中使用了下面的方法
下面是我创建输入的方式
<form className={styles.root} noValidate autoComplete="off">
<input
name="avatar_image" // name of input field or fieldName simply
enctype="multipart/form-data"
type="file"
onChange={(event) => {
// console logging selected file from menu
console.log( event.target.files[0] ) // gives first file
// setState method with event.target.files[0] as argument
this.setState(prev => ({...prev, user_image: event.target.files[0]}))
}}
/>
</form>
以下是我向后端发出请求的方式
const formData = new FormData()
formData.append('user_name', this.state.user_name)
formData.append('phone_number', this.state.phone_number)
// now below avatar_image is the fieldName of the image, then comes the file to upload, and the file name in the end
formData.append('avatar_image', this.state.user_image, this.state.user_image.name)
axios.post(utils.baseUrl + '/avatar-uploads/avatar-image-upload', formData, {
onUploadProgress: progressEvent => {
console.log( 'upload progress: ' + Math.round((progressEvent.loaded / progressEvent.total)*100) + '%' )
}
})
.then(function (response) {
// further code
})
.catch(function (error) {
console.log(error);
});
下面是我如何使用 multer 处理 backned,包括处理 payload
const image_storage = multer.diskStorage({
destination: path.join(__dirname , '../../assets/images/uploads/avatar_image'),
filename: function(req, file, cb){
cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname))
}
});
// Init Upload
const user_avatar_image_upload = multer({
storage: image_storage,
limits:{fileSize: 2000000}, // 1 mb
fileFilter: function(req, file, cb){
checkFileTypeForUserAvatar(file, cb);
}
}).single('avatar_image'); // this is the fieldName that will be dealt
// Check File Type
function checkFileTypeForUserAvatar(file, cb){
// Allowed ext
let filetypes = /jpeg|jpg|png|gif/;
// Check ext
let extname = filetypes.test(path.extname(file.originalname).toLowerCase());
// Check mime
let mimetype = filetypes.test(file.mimetype);
if(mimetype && extname){
return cb(null,true);
} else {
cb('Error: jpeg, jpg, png, gif Images Only!');
}
}
// router.post('/protected-avatar-image-upload', passport.authenticate('jwt', { session: false }), (req, res, next) => {
router.post('/avatar-image-upload', (req, res, next) => {
console.log(req.body) // here the req.body will turn out {}
user_avatar_image_upload(req, res, (err) => {
if(err){
console.log(err)
} else {
if(req.file == undefined){
res.status(404).json({ success: false, msg: 'File is undefined!',file: `uploads/${req.file.filename}`})
} else {
console.log( req.body.user_name ) // here req.body.user_name and others will work
// further code
res.status(200).json({ success: true, msg: 'File Uploaded!',file: `uploads/${req.file.filename}`})
}
}
})
})
希望这有助于如何使用 multer 上传文件,并传递额外的有效负载,以便它也可以用于创建数据库条目或其他任何东西。