在实现上传接口的时候,需要了解一下上传的过程跟需要依赖的库,以及测试上传需要注意的问题。这里顺便说一下,注册的时候去掉默认的图片头像了,还有默认的签名。
图片上传到服务器的逻辑
首先前端调用上传接口,将上传的资源经过 FormData 实例封装之后,传给服务端
在服务端接收前端传进来的图片信息,通过 fs.readFileSync 方法,来读取图片内容,并存放在变量中
找个存放图片的公共位置
通过 fs.writeFileSync 方法,将图片内容写入公共位置
最后返回图片地址
依赖的库
需要对:fs、moment、path、mkdirp,有一定了解,fs,path 大家应该比较熟悉了,这里就对 moment 以及 mkdirp 做一下简单的介绍,具体的可以查看文档:
mkdirp
mkdirp 是一款在 node.js 中像 mkdir -p 一样递归创建目录及其子目录。
安装
npm install -g mkdirp
使用
var mkdirp = require('mkdirp'); mkdirp('/tmp/foo/bar/baz', function (err) { if (err) console.error(err) else console.log('kaimo') }); // 输出 kaimo,/tmp/foo/bar/baz 目录就会出现。
moment
Moment.js 是一个轻量级的 JavaScript 时间库,它方便了日常开发中对时间的操作,提高了开发效率。
安装
npm install moment
使用
var moment = require('moment'); moment().format(); // 格式化日期时间 moment(value).format('YYYY-MM-DD HH:mm:ss'); // moment(Date):可以使用预先存在的原生 Javascript Date 对象来创建 Moment。 var day = new Date(2011, 9, 16); var dayWrapper = moment(day); // 这会克隆 Date 对象,Date 的后续更改不会影响 Moment,反之亦然。
eggjs 里文件上传接收
egg 获取上传文件的方法中官方给了两种处理方法:这里采用用 file 直接读取
- file 直接读取
- stream 流的方式:创建文件写入流,以管道方式写入流
file 读取方式
需要先在 config.defult.js 里配置:
config.multipart = { mode:'file' };
控制层代码:
// file 包含了文件名,文件类型,大小,路径等信息 // files[0]表示获取第一个文件,若前端上传多个文件则可以遍历这个数组对象 let file = ctx.request.files[0] // 读取文件 let filedata = fs.readFileSync(file.filepath); // 将文件存到指定位置 fs.writeFileSync(path.join('./', `uploadfile/test.png`), filedata)
关于 stream 流的方式可以参考:【egg文件上传接收总结】
上传接口实现
0、配置
需要先在 config.defult.js 里配置:文件读取配置,以及上传头像路径,我们单独把头像放到本地的 kaimo-cost-images 文件夹里,跟项目分开,就不放到app的public文件夹里了,这个不需要手动去 D 盘创建文件夹,到时会自动生成的。
// add your user config here const userConfig = { // myAppName: 'egg', uploadAvatarDir: 'D://kaimo-cost-images/images/avatar', // 上传头像路径 }; // 文件读取配置 config.multipart = { mode: 'file' };
1、新建路由
配置完,开始去 router.js 文件里写一下请求上传的路由
// 上传头像 router.post('/api/upload/avatar', verify_token, controller.upload.uploadAvatar);
2、新建 upload.js 文件
在 controller 文件夹下新建 upload.js 用于处理上传的相关逻辑
3、编写上传逻辑
- 获取文件,
ctx.request.files[0]表示获取第一个文件,若前端上传多个文件则可以遍历这个数组对象 - 获取当前日期
- 创建图片保存的路径
- 创建目录
- 生成路径返回
- 写入文件夹
- 清除临时文件,
ctx.cleanupRequestFiles();
'use strict'; const fs = require('fs'); const path = require('path'); const moment = require('moment'); const mkdirp = require('mkdirp'); const Controller = require('egg').Controller; class UploadController extends Controller { async uploadAvatar () { const { ctx, config } = this; try { // 0、获取文件 let file = ctx.request.files[0]; console.log('获取文件', file); // ctx.request.files[0] 表示获取第一个文件,若前端上传多个文件则可以遍历这个数组对象 let fileData = fs.readFileSync(file.filepath); console.log('fileData', fileData); // 1、获取当前日期 let day = moment(new Date()).format('YYYYMMDD'); console.log('1、获取当前日期', day); // 2、创建图片保存的路径 let dir = path.join(config.uploadAvatarDir, day); console.log('2、创建图片保存的路径', dir); // 3、创建目录 await mkdirp(dir); // 4、生成路径返回 let date = Date.now(); // 毫秒数 let tempDir = path.join(dir, date + path.extname(file.filename)); // 返回图片保存的路径 console.log('毫秒数 extname', date, path.extname(file.filename)); console.log('返回图片保存的路径', tempDir); // 5、写入文件夹 fs.writeFileSync(tempDir, fileData); ctx.body = { status: 200, desc: '上传成功', data: tempDir, } } catch(error) { ctx.body = { status: 500, desc: '上传失败', data: null } } finally { // 6、清除临时文件 ctx.cleanupRequestFiles(); } } } module.exports = UploadController;
测试接口
还是老样子,先登录,然后拿到 token,在上传一张图片,比如我选择一只修勾勾,然后点击发送。
我们可以看到成功返回了图片所在的路径。当然实际项目里不会返回服务器的路径的,下一节我们在优化处理。
接下来,看看 D 盘是否生成了文件夹跟保存了图片。我们发现是保存成功了。




