antd pro 系列之二 : 使用egg 搭建后台
-
缘起:
为了搭建完整的web 应用,技术选型后台使用 egg , 所以在这里记录一下egg 搭建后台的过程;
-
背景:
egg是基于koa 进行封装的; egg也是采用了koa 的中间件机制;不像node社区的那些全面封装的node 应用,像那种数据库、web 前端都封装好的框架; egg采取了更灵活的形式,方便开发者进行个性化的定制开发;
因为之前自己也是做过node 项目的,主要是使用koa2实现管理系统,基本的技术栈是koa2 + mysql ,开发方式比较简单,数据库的操作还是使用原始的sql 语句进行实现;
为了迎和当今的开发潮流,所以有必要使用egg 作为restfull api 的开发;
上述reposity 是restfull api 的模板实现;
- egg实现文件上传:
dom 界面直接调用Upload 组件即可, 通常来说,文件上传是有一些要求的,比如说只支持jpg 类型的上传,所以要添加beforeUpload 方法进行限制,最后通过表单的形式封装成formData 来进行文件的上传;
web 代码:
<Form action='/upload' method='post'>
<Form.Item>
<Upload
{...props}
>
<Button icon={<UploadOutlined />}>Click to Upload</Button>
</Upload>
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" onClick={upload}>
提交
</Button>
</Form.Item>
</Form>
通过form 表单的形式对文件进行上传,并可以在props 中添加对文件的限制;
props代码 , && form 的submit 方法;
const props = {
name: 'file',
action: '/api/upload',
onChange(info) {
if (info.file.status !== 'uploading') {
console.log(info.file, info.fileList);
setuploadfileList(info.fileList);
}
if (info.file.status === 'done') {
message.success(`${info.file.name} file uploaded successfully`);
} else if (info.file.status === 'error') {
message.error(`${info.file.name} file upload failed.`);
}
},
}
const upload = () => {
if (uploadfileList.length) {
const formData = new FormData()
formData.append('参数名', uploadfileList[0]);
console.log(uploadfileList[0]);
// fetch 请求;
fetch('/api/upload', {
method: 'post',
body:formData,
})
.then(res => {
console.log('res信息:',res);
if(res.status === 200) {
alert('文件上传成功');
}else {
alert('文件上传失败');
}
})
}
}
因为后端的端口是7001 , 所以需要设置一下proxy , 在config 文件夹中进行设置;
应用实现的方式是获取请求的文件流对象并调用fs 模块写文件;代码是:
async create() {
const { ctx, service } = this
const stream = await ctx.getFileStream()
const filename = path.basename(stream.filename)
const extname = path.extname(stream.filename).toLowerCase()
const attachment = new this.ctx.model.Attachment
attachment.extname = extname
attachment.filename = filename
attachment.url = `/uploads/${attachment._id.toString()}${extname}`
const target = path.join(this.config.baseDir, 'app/public/uploads', `${attachment._id.toString()}${attachment.extname}`)
const writeStream = fs.createWriteStream(target)
try {
await awaitWriteStream(stream.pipe(writeStream))
} catch (err) {
// 必须将上传的文件流消费掉,要不然浏览器响应会卡死
await sendToWormhole(stream)
throw err
}
const res = await service.upload.create(attachment)
ctx.helper.success({ctx, res})
}
最终写入应用端的uploads 文件夹下面,因为对文件进行了重命名,所有uloads 下面的文件名和上传的文件名是不一致的;
这个还是最简单的文件上传, 关于文件上传组件会涉及到分片上传,断点续传等业务逻辑的实现;
- 大文件分片上传:
后端需要接收formData 并写入文件,因为文件是分片的,所以需要对分片的文件进行合并,写一个合并的函数:
// 合并文件
const mergeFiles = () => {
if (index === chunkOrder.length) {
writeStream.end();
fs.removeSync(readPath);
return;
}
const readStream = fs.createReadStream(path.join(readPath, chunkOrder[index]));
readStream.pipe(writeStream, { end: false });
readStream.on('end', () => {
index += 1;
mergeFiles();
});
};
按照chunkOrder 的顺序合并文件,最后在写入一个文件; web 是使用功能vue 进行实现的, 准备使用react 重写;
web 的代码就先不展示了 , 这里说一下需要实现的功能点: 因为文件是分片的,分片的数量由前端进行设置; 通过传参数的形式进行设计;
- summary:
egg作为后端自己也只是刚刚开始,后面参考文档继续实现新的功能,结合mongodb 来搭建中后台系统,后面会继续更新,欢迎关注;
个人公众号:
欢迎关注;