文件上传是开发中不可避免的一项。那么在没有单独的资源服务器的时候,上传的文件可能要放在我们的项目文件夹服务器上,我们如何实现文件上传呢?
首先不用想,我们需要一个测试页面。html用来上传文件。如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>图片上传</title>
</head>
<body>
<input type="file" id='upload' />
<script>
// 获取 input 标签的 dom
var input = document.getElementById('upload')
// 监听它的变化
input.addEventListener('change', function(e) {
// 获取到上传的 file 对象
var file = input.files[0]
// 声明 FormData 实例 formData
let formData = new FormData()
// 添加实例属性 file
formData.append('file', file)
console.log('formData', formData)
// 调用服务端上传接口。
fetch('http://localhost:7001/api/upload', {
method: 'POST',
body: formData
}).then(res => {
if(res.ok) {
console.log('success')
return res.json();
} else {
console.log('error')
}
}).then(res => {
console.log('res is', res);
})
})
</script>
</body>
</html>
其次我们需要安装 moment mkdirp 用来实现时间转换以及文件夹创建
npm i moment mkdirp -S
下来,我们就必须要考虑下上传文件的流程。
-
我们需要在前端调选择文件,调用接口并且将图片带上。
-
在服务端接收到发来的图片信息的时候,我们需要获取到图片内容。
-
在当前项目找个目录将图片放进去,一般都会放在 app/public/upload 下。
-
将获取到的图片内容放入到指定的目录下。
-
返回上传文件的地址。服务器地址 + 图片名称 + 后缀
我们需要在服务端中确定文件的接收方式,这里我们采用file 模式。也就是文件接收模式
前往config/config.default.js 配置文件的接收形式
config.multipart = {
mode: 'file'
}
其中 multipart 的配置有许多,如 上传格式的定制,文件大小的限制等。
详细的,大家可以在官网进行查询 文件上传 | Egg
配置完成后。我们的开发流程如下:
- 通过ctx.request.files的形式,获取到前端上传文件的文件资源。
- 通过fs.readFileSync(file.filepath) 来读取文件内容。
- 然后在全局配置公共资源文件存放位置。获取这个位置。
// config.default.js
const userConfig = {
// myAppName: 'egg',
uploadDir: 'app/public/upload',
};
- 使用 this.config.uploadDir 获取位置目录
- 将文件名加入到这个目录下获取最终生成的路径
- 将文件写入到最终路径下
- 上传成功。
所以我们的代码就如下:
新建controller/ upload.js
const fs = require('fs') // 引入fs,node 自带的文件处理工具
const moment = require('moment') // 引入moment 时间处理工具
const mkdirp = require('mkdirp') // 引入文件夹处理工具
const path = require('path') // 引入路径处理工具
const Controller = require('egg').Controller;
class UploadController extends Controller {
async upload() {
const { ctx } = this
// 1 获取我们上传文件。 是一个数组,只有一个文件情况下,默认为数组中的下标0。
let file = ctx.request.files[0]
// 2 声明存放资源的路径
let uploadDir = ''
try {
// 3 读取文件内容
let f = fs.readFileSync(file.filepath)
// 4 获取当前日期
let day = moment(new Date()).format('YYYYMMDD')
// 5 生成文件最后要保存的路径地址
let dir = path.join(this.config.uploadDir, day);
await mkdirp(dir); // 6 这个方法是,如果 上述dir 路径存在,那就不创建,如果不存在则会创建这个对应目录文件夹
// 7 返回图片保存的完整路径
uploadDir = path.join(dir,file.filename);
// 8 将图片内容写入到文件夹下
fs.writeFileSync(uploadDir, f)
} finally {
// 清除临时文件
ctx.cleanupRequestFiles();
}
ctx.body = {
code: 200,
msg: '上传成功',
data: uploadDir.replace(/app/, ''),// 删除 /app/ 这个目录
}
}
}
module.exports = UploadController;
我们打开刚开始的上传文件html模板进行测试
选择文件后
我们使用服务器地址+ 返回的图片链接尝试访问
访问成功。任务结束。