Angular提交FormData上传文件到Node.js接口时req.body为空的解决方法
Angular提交FormData上传文件时Node.js端req.body为空的解决方案
问题描述
我正从Angular向Node.js端点POST两个字段。
平时我直接在请求体中提交参数,Node端可以正常获取,但这次我需要提交表单来上传文件。
以下是我最初Angular端提交FormData的代码:
var APIURL = sessionStorage.getItem('endPoint') + "profile/updateeocoverage"; let formData = new FormData(); formData.append("data", JSON.stringify(this.payLoad)); if (this.eofile) { formData.append("myfile", this.eofile, this.eofile.name); } this.httpClient.post(APIURL, formData).subscribe( result => { // 后续逻辑 ....
我的问题是Node端按如下方式获取请求体时,返回的req.body是空对象{}:
router.post('/updateeocoverage', async (req, res, next) => { console.log(req.body) return; // 后续逻辑 ....
解决方法
使用Multer可以解决该问题,不过需要做额外配置来指定文件名,同时还需要实现用户鉴权,避免接口被恶意调用,具体实现如下:
1. 引入依赖
const multer = require('multer') const path = require('path')
2. 实现用户鉴权逻辑
为了实现用户鉴权,我把鉴权参数放在请求头中传递,测试下来通过formdata.append的方式传参无法被鉴权逻辑正常读取。鉴权逻辑会返回是否允许上传,防止未授权用户调用接口上传文件:
async function authenticateUser(req, file, cb) { let tempcred = JSON.parse(req.headers.data) let credentials = tempcred.credentials; let userData = await utils.isValidUser((credentials), false); if (userData.isValid == false) { cb(null, false) return; } else { cb(null, true) } }
3. 配置Multer存储规则
由于Multer默认会给上传的文件生成随机文件名,而我需要用用户ID加原文件扩展名来保存文件,因此做了如下配置:
var storage = multer.diskStorage({ destination: function (req, file, cb) { cb(null, 'uploads/eofiles/') }, filename: async function (req, file, cb) { let tempcred = JSON.parse(req.headers.data) let credentials = tempcred.credentials; let userid = await utils.decrypt(credentials.userid, process.env.SECRET); cb(null, userid + path.extname(file.originalname)) } });
4. 初始化Multer实例
var upload = multer({ storage: storage, fileFilter: authenticateUser })
5. 调整路由配置
注意upload.single("myfile")中的参数myfile对应前端FormData里文件字段的键名:
router.post('/updateeofile', upload.single("myfile"), async (req, res, next) => { let filename = req.file.filename // 获取保存的文件名 ... // 后续业务逻辑,比如将文件信息存入数据库等 ... });
6. 调整Angular端上传代码
var APIURL = sessionStorage.getItem('endPoint') + "eoset/updateeofile"; const httpOptions = { headers: new HttpHeaders({ 'data': `${JSON.stringify(this.payLoad)}` }) }; let formData = new FormData(); if (this.eofile) { formData.append("myfile", this.eofile, this.eofile.name); } this.httpClient.post(APIURL, formData, httpOptions).subscribe( result => { // 成功回调逻辑 ... }, error => { // 错误处理逻辑 });
我今天在这个问题上花了6个小时,希望这篇内容能帮你节省时间。
内容的提问来源于stack exchange,提问作者Danielle
相关产品推荐
相关产品推荐

