Node.js - 上传文件



在许多 Web 应用程序中,用户需要从客户端计算机上传文件(例如用户使用 Facebook 或 Instagram 应用程序上传图像和视频)到服务器。NPM 注册表上有许多可用的开源模块,通过这些模块,可以在Node.js应用程序中启用上传文件的功能。这个 Formidable  模块提供了一个方便的 API 来处理文件上传。Formidable 模块可以与内置的 http 模块以及 Express 应用程序一起导入到核心 Node.js 模块中。

Formidable

Formidable 模块是一个快速且流式的多部分解析器,能够自动将文件上传写入磁盘。它具有低内存占用,具有高效的错误处理机制。

作为第一步,使用以下命令安装强大的模块 -

npm install formidable

在本章中,Formidable 模块在包含 http 模块的 node.js 应用程序和 ExpressJs 应用程序中的示例用法如下所示 -

带有Node.js HTTP 模块

以下示例调用 createServer() 函数来启动 Node.JS 服务器,并呈现一个多部分 HTML 表单,供用户选择要上传的文件。

提交文件时,将解析表单数据,并将上传的文件复制到磁盘中的默认位置。


var http = require('http');
var formidable = require('formidable');

var errors = formidable.formidableErrors;

const server = http.createServer(async (req, res) => {
	 	if (req.url === '/api/upload' && req.method.toLowerCase() === 'post') {
	 	 	 // parse a file upload
	 	 	 const form = new formidable.IncomingForm();
	 	 	 let fields;
	 	 	 let files;
	 	 	 try {
	 	 	 	 	[fields, files] = await form.parse(req);
	 	 	 } catch (err) {

	 	 	 	 	res.writeHead(err.httpCode || 400, { 'Content-Type': 'text/plain' });
	 	 	 	 	res.end(String(err));
	 	 	 	 	return;
	 	 	 }
	 	 	 res.writeHead(200, { 'Content-Type': 'application/json' });
	 	 	 res.end(JSON.stringify({ fields, files }, null, 2));
	 	 	 return;
	 	}

	 	// show a file upload form
	 	res.writeHead(200, { 'Content-Type': 'text/html' });
	 	res.end(`
	 	 	 <h2>With Node.js <code>"http"</code> module</h2>
	 	 	 <form action="/api/upload" enctype="multipart/form-data" method="post">
	 	 	 <div>Text field title: <input type="text" name="title" /></div>
	 	 	 <div>File: <input type="file" name="multipleFiles" multiple="multiple" /></div>
	 	 	 <input type="submit" value="Upload" />
	 	 	 </form>
	 	`);
});
server.listen(5000, () => {
	 	console.log('Server listening on http://localhost:5000/ ...');
});

在应用程序运行时,浏览器会显示以下表单,以选择要上传的文件。

Nodejs http 模块

上传操作成功后,浏览器显示以下结果 -


{
	 "fields": {
	 	 	 "title": [
	 	 	 	 	"test"
	 	 	 ]
	 	},
	 	"files": {
	 	 	 "multipleFiles": [
	 	 	 	 	{
	 	 	 	 	 	 "size": 4203211,
	 	 	 	 	 	 "filepath": "C:\\Users\\user\\AppData\\Local\\Temp\\930f2f754006b790729e0d200",
	 	 	 	 	 	 "newFilename": "930f2f754006b790729e0d200",
	 	 	 	 	 	 "mimetype": "image/png",
	 	 	 	 	 	 "mtime": "2023-12-24T08:04:09.856Z",
	 	 	 	 	 	 "originalFilename": "1.png"
	 	 	 	 	}
	 	 	 ]
	 	}
}

与Express.js

在Express.JS代码中,Formidable 模块的最简单用法如下 -


import express from 'express';
import formidable from 'formidable';

const app = express();

app.get('/', (req, res) => {
	 	res.send(`
	 	 	 <h2>With <code>"express"</code> npm package</h2>
	 	 	 <form action="/api/upload" enctype="multipart/form-data" method="post">
	 	 	 <div>Text field title: <input type="text" name="title" /></div>
	 	 	 <div>File: <input type="file" name="someExpressFiles" multiple="multiple" /></div>
	 	 	 <input type="submit" value="Upload" />
	 	 	 </form>
	 	`);
});
app.post('/api/upload', (req, res, next) => {
	 	const form = formidable({});

	 	form.parse(req, (err, fields, files) => {
	 	 	 if (err) {
	 	 	 	 	next(err);
	 	 	 	 	return;
	 	 	 }
	 	 	 res.json({ fields, files });
	 	});
});

app.listen(5000, () => {
	 	console.log('Server listening on http://localhost:5000 ...');
});

您也可以在上传过程中安装并使用 body-parser 模块来解析多部分 HTML 表单数据。

Multer

另一个能够处理文件上传的有用 NPM 模块称为 Multer。用户可以一次上传单个或多个文件。

要安装,请使用以下命令 -

npm install multer

在 Express 应用的开头,包含 muletr 并声明 Multer 对象。


const multer 	= require('multer')
const upload = multer({ dest: 'uploads/' })

假设您有一个处理GET请求的路由,并显示一个多部分HTML表单,该表单将表单发布到/upload路由,请添加以下函数来处理POST请求 -


app.post("/upload", upload.single("myFile"), (req, res) => {
	 	console.log("Body: ", req.body);
	 	console.log("File: ", req.file);
	 	res.send("File successfully uploaded.");
});

要将上传的文件存储在指定位置而不是临时文件的默认位置,请配置Multer位置,如下所示 -


var storage = multer.diskStorage({ 		
	 	destination: function(req, file, cb) {	
	 	 	 // destination is used to specify the path of the directory in which the files have to be stored
	 	 	 cb(null, './uploads'); 	 	
	 	},	
	 	filename: function (req, file, cb) {	
	 	 	 // It is the filename that is given to the saved file.
	 	 	 cb(null , file.originalname); 		
	 	}
});

// Configure storage engine instead of dest object.
const upload = multer({ storage: storage })