antd pro 系列之二 : 使用egg 搭建后台

322 阅读3分钟

antd pro 系列之二 : 使用egg 搭建后台

  • 缘起:

    为了搭建完整的web 应用,技术选型后台使用 egg , 所以在这里记录一下egg 搭建后台的过程;

    德云社

  • 背景:

egg是基于koa 进行封装的; egg也是采用了koa 的中间件机制;不像node社区的那些全面封装的node 应用,像那种数据库、web 前端都封装好的框架; egg采取了更灵活的形式,方便开发者进行个性化的定制开发;

因为之前自己也是做过node 项目的,主要是使用koa2实现管理系统,基本的技术栈是koa2 + mysql ,开发方式比较简单,数据库的操作还是使用原始的sql 语句进行实现;

为了迎和当今的开发潮流,所以有必要使用egg 作为restfull api 的开发;

github.com/heimi-block…

上述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 来搭建中后台系统,后面会继续更新,欢迎关注;

个人公众号: qrcode_for_gh_7c727e9e9e7c_258 1.jpg

欢迎关注;