原文链接
搬砖的林小白-express的使用(四)
个人博客地址,求关注,也希望大家在里面批评我的不足之处
看前提示
本篇所讲述的内容是node端转发前端发送过来的表单到第三方中,应用的场景有很多,如我们经常做的将文件存储到七牛云或者amazon等服务上。我们常规的流程是:在nodejs 端中获取到前端传过来的表单文件,并将其存放到内存中,接着发送到第三方服务,下面的博客也是按照这样的流程来写。
本次工作的重点放在了node端转发表单文件到另一方去,因此,对于一开始的前端发送表单文件以及最后的第三方接受表单文件就不详细叙述,只是简单的贴上代码
依赖版本
"axios": "^1.4.0",
"express": "^4.18.2",
"multer": "^1.4.5-lts.1"
前端表单提交
前端的代码依旧按照上一篇博客的操作,直接使用postman提交一个表单数据,如下所示,依旧是一个form-data的格式,且字段为file,文件为一个jpg文件
curl --location --request POST 'http://localhost:3000/user/fileUpload' --form 'file=@"/C:/Users/34714/Documents/DSC05948.JPG"'
模拟第三方接接收文件
在后端的代码中,用multer以及express构建一个接收multipart/form-data请求的简单接口,代码如下
const express = require("express");
const app = express();
const multer = require("multer");
const upload = multer({
storage: multer.diskStorage({
// 将文件存储在uploads下面
destination: function (req, file, cb) {
cb(null, "uploads");
},
// 保存文件的原始名字
filename: function (req, file, cb) {
cb(null, file.originalname);
},
}),
});
// 文件上传api
app.post("/mockFileUpload", upload.single("file"), (req, res, next) => {
console.log("模拟的后台端获取到的信息是===================>");
console.log(req.file);
if (req.file) {
console.log(`文件的名字是${req.file.originalname}`);
} else {
console.log(`没有收到文件`);
}
});
app.listen(3001, () => {
console.log("服务3001已启动");
});
{
"name": "demo2",
"version": "1.0.0",
"main": "server.js",
"dependencies": {
"express": "^4.18.2",
"multer": "^1.4.5-lts.1",
"nodemon": "^2.0.22"
},
"scripts": {
"test": "echo Error: no test specified && exit 1",
"dev": "nodemon server.js"
},
"author": "",
"license": "ISC",
"description": ""
}
nodejs 端代码
在上一篇的文件接收的基础上,我们需要做一些细微的改动,比如
1.文件只保存在内存中,并不保存于磁盘中,理由很简单,如果没有删除文件,会防止内存爆炸,又或者用户并发量很大,磁盘的读取很频繁,这会让我们收到很多的警报,搞不好可能要导致宕机,然后频繁的跟领导聊人生,又或者因为设置的文件夹没有读写权限而产生bug等。所以直接限制文件的大小,以及将文件存储在内存中,而不将其存储于内存中,在生产环境中是一个最适合的选择。
const upload = multer({});
2.当我们在后端构建一个表单提交的请求时,有前端开发经验的朋友可以很容易的知道,我们需要构建一个formData来存储我们的数据,而node端是没有formData这个方法的,所以我们需要借助form-data这个库来构建一个表单提交
const formData = require("form-data");
此时,先让我们观察下接收到的file有哪些字段
看结构,我们可以看到文件的’内容’放在了buffer中,也想到了文档中有下面这些一句代码
那么,我们姑且将得到的buffer使用append进去
router.post("/fileUpload", upload.single("file"), (req, res, next) => {
console.log("文件的信息是===================>");
console.log(req.file);
const form = new FormData();
form.append("file", req.file.buffer);
});
接着,再用上我们很是习惯的axios,将请求发送出去。
// 文件上传api
router.post("/fileUpload", upload.single("file"), async (req, res, next) => {
console.log("文件的信息是===================>");
console.log(req.file);
const form = new FormData();
form.append("file", req.file.buffer);
await axios({
url: "http://localhost:3001/mockFileUpload",
method: "post",
data: form,
headers: {
"Content-Type": "multipart/form-data",
},
});
});
运行项目,让我们在另一个程序中,查看下返回的结果
因此,可以理解用这种方式传输的时候,经过踩坑(查看了下buffer以及stream等的一些属性)之后,发现了form-data的append这个方法可以传三个参数。
如果如此,第二个参数可以使用我们获得到的buffer,而第三个参数,按照文档的提示,只能且行且试了,将我们multer获取到的文件的参数一一放进去
form.append('file', stdout, {
filename: 'unicycle.jpg', // ... or:
filepath: 'photos/toys/unicycle.jpg',
contentType: 'image/jpeg',
knownLength: 19806
});
最后组合的代码如下
router.post("/fileUpload", upload.single("file"), async (req, res, next) => {
console.log("文件的信息是===================>");
console.log(req.file);
const form = new FormData();
form.append("file", req.file.buffer, {
filename: req.file.originalname,
contentType: req.file.mimetype,
knownLength: req.file.knownLength,
});
await axios({
url: "http://localhost:3001/mockFileUpload",
method: "post",
data: form,
headers: {
"Content-Type": "multipart/form-data",
},
});
});
运行过后,在模拟后台中看到了下面的两个面板
由此可见,node端也是可以转发一个form-data出去的,如果跟后台沟通出了问题,建议直接丢这个模板给他。
最后再贴上一遍完整的代码
const express = require("express");
const router = express.Router();
const multer = require("multer");
const upload = multer({});
const FormData = require("form-data");
const { default: axios } = require("axios");
// 文件上传api
router.post("/fileUpload", upload.single("file"), async (req, res, next) => {
console.log("文件的信息是===================>");
console.log(req.file);
const form = new FormData();
form.append("file", req.file.buffer, {
filename: req.file.originalname,
contentType: req.file.mimetype,
knownLength: req.file.knownLength,
});
await axios({
url: "http://localhost:3001/mockFileUpload",
method: "post",
data: form,
headers: {
"Content-Type": "multipart/form-data",
},
});
});
module.exports = {
userRouter: router,
};
参考链接
multer/README-zh-cn.md at master · expressjs/multer · GitHub
form-data - npm (npmjs.com)
注意事项
暂无