Hapi 是一个 Node.js 的 Web 应用框架,其提供了一个强大、具有可扩展性的插件架构,使它成为了一个优秀的选择。其中,多文件上传及文件下载功能是 Web 应用开发中常见的需求之一。本文将介绍如何在 Hapi 框架中实现多文件上传和文件下载,可供开发者参考学习。
多文件上传实现
多文件上传需要使用 hapi-payload-plugin
插件,在服务器端接收文件,并将文件保存至服务端。其中,三个关键点是:
- 设置路由接口,定义上传的接口;
- 配置
hapi-payload-plugin
插件,使其支持多文件上传; - 编写文件上传功能的处理代码。
设置路由接口
首先需要设置路由接口,接收上传的文件:
// javascriptcn.com 代码示例 server.route({ method: 'POST', path: '/upload', handler: async (request, h) => { // 文件上传逻辑 }, config: { payload: { output: 'stream', parse: true, allow: ['multipart/form-data'] } } });
此处我们定义了一个 /upload
的路由接口,用于接收文件上传请求。其中,我们必须设置 payload
配置项, output: 'stream'
表示将文件流上传到服务端; parse: true
表示将上传的数据转化为对象; allow: ['multipart/form-data']
即表单类型为 multipart/form-data
,支持文件上传。
配置 hapi-payload-plugin
插件
接下来需要安装并注册 hapi-payload-plugin
插件,才能使服务端支持多文件上传功能。在安装插件后,在服务启动文件中注册插件。
// javascriptcn.com 代码示例 const Hapi = require('hapi'); const Payload = require('hapi-payload-plugin'); const server = new Hapi.Server({ port: 8080, host: 'localhost' }); const init = async () => { await server.register({ plugin: Payload, options: { validate: true, fastify: false } }); await server.start(); } init();
完成以上配置后,就可以在 handler
函数中读取上传的文件,并将文件保存至服务端。
上传代码实现
// javascriptcn.com 代码示例 handler: async (request, h) => { const payload = request.payload; // 获取上传的 payload if (!payload.file) { return h.response({ message: 'No file uploaded' }).code(400); } const data = payload.file; // 获取上传的文件 // 处理文件 const uploadPath = './uploads/'; // 设置上传路径 await mkdirpAsync(uploadPath); //创建目录 const filename = `${new Date().getTime()}-${data.hapi.filename}`; //设置文件名 const path = `${uploadPath}/${filename}`; //设置文件路径 const file = fs.createWriteStream(path); //创建可写流 return new Promise((resolve, reject) => { data.pipe(file); //上传文件 data.on('end', () => { const fileDetails = { name: data.hapi.filename, path }; resolve(fileDetails); }); data.on('error', (err) => { reject(err); }); }); }
完整的多文件上传代码
// javascriptcn.com 代码示例 const Hapi = require('hapi'); const Payload = require('hapi-payload-plugin'); const fs = require('fs'); const mkdirp = require('mkdirp'); const util = require('util'); const server = new Hapi.Server({ port: 8080, host: 'localhost' }); const init = async () => { await server.register({ plugin: Payload, options: { validate: true, fastify: false } }); server.route({ method: 'POST', path: '/upload', handler: async (request, h) => { const payload = request.payload; if (!payload.file) { return h.response({ message: 'No file uploaded' }).code(400); } const data = payload.file; const uploadPath = './uploads/'; await mkdirpAsync(uploadPath); const filename = `${new Date().getTime()}-${data.hapi.filename}`; const path = `${uploadPath}/${filename}`; const file = fs.createWriteStream(path); return new Promise((resolve, reject) => { data.pipe(file); data.on('end', () => { const fileDetails = { name: data.hapi.filename, path }; resolve(fileDetails); }); data.on('error', (err) => { reject(err); }); }); }, config: { payload: { output: 'stream', parse: true, allow: ['multipart/form-data'], maxBytes: 5242880 } } }); await server.start(); } const mkdirpAsync = util.promisify(mkdirp); init();
文件下载实现
文件下载需要使用 hapi
框架提供的 file()
方法。在路由配置中使用 file()
方法即可完成文件下载功能。
设置路由接口
// javascriptcn.com 代码示例 server.route({ method: 'GET', path:'/download/{file*}', handler: { file: async (request) => { return `./uploads/${request.params.file}`; } } });
此处我们定义了一个 GET
接口,用于下载 ./uploads/
目录下的文件。使用 handler
配置项,通过 file()
方法设置返回文件路径。注意,这里的 {file*}
是一个通配符,在实际使用时可以根据需求修改。
完整的文件下载实现代码
// javascriptcn.com 代码示例 const Hapi = require('hapi'); const server = new Hapi.Server({ port: 8080, host: 'localhost' }); const init = async () => { server.route({ method: 'GET', path:'/download/{file*}', handler: { file: async (request) => { return `./uploads/${request.params.file}`; } } }); await server.start(); } init();
总结
本文介绍了如何在 Hapi 框架中实现多文件上传和文件下载功能。需要注意以下几点:
- 需要使用
hapi-payload-plugin
插件,才能支持多文件上传功能; - 使用
hapi
提供的file()
方法,将服务端文件托管,即可实现文件下载。
Hapi 框架具有可扩展性的插件架构,使得开发者可以方便地进行二次开发。希望通过本文的介绍,能对开发者掌握 Hapi 框架的相关能力和开发实践提供一些帮助。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/654a3d607d4982a6eb4632b1