[代码地址](https://github.com/dirkhe1051931999/common-demo) 服务端接口以及中间件 依赖的包 const Koa = require('koa'); // 解析成json const koaJson = require('koa-json'); // 解析body的 const bodyParser = requir

[代码地址](https://github.com/dirkhe1051931999/common-demo)

服务端接口以及中间件

  • 依赖的包
const Koa = require('koa');
// 解析成json
const koaJson = require('koa-json');
// 解析body的
const bodyParser = require('koa-bodyparser');
// 静态资源库
const resource = require('koa-static');
// 设置session的
const session = require('koa-session');
const path = require('path');

const Router = require('koa-router');
const upload = require('./upload');
const app = new Koa();
let router = new Router();
  • 装载 session
// session使用前的一些设置
app.keys = ['some secret hurr'];
const CONFIG = {
  key: 'koa:sess', //cookie key (default is koa:sess)
  maxAge: 86400000, // cookie的过期时间 maxAge in ms (default is 1 days)
  overwrite: true, //是否可以overwrite    (默认default true)
  httpOnly: true, //cookie是否只有服务器端可以访问 httpOnly or not (default true)
  signed: true, //签名默认true
  rolling: false, //在每次请求时强行设置cookie,这将重置cookie过期时间(默认:false)
  renew: false //(boolean) renew session when session is nearly expired,
};
app.use(session(CONFIG, app));
  • 上传图片接口
router.post('/upload', async (ctx) => {
  let result;
  try {
    result = await upload.uploadFile(ctx);
    ctx.body = {
      success: 0,
      message: result.filePath
    };
  } catch (error) {
    ctx.body = {
      success: 1,
      message: '缺少参数'
    };
  }
});
  • upload.js
// upload.js
const fs = require('fs');
const path = require('path');
const moment = require('moment');
const formidable = require('formidable');
const config = {
  root: path.normalize(__dirname),
  appPath: 'static',
  tempUploads: 'tempUploads',
  uploads: 'uploads'
};

function mkdirsSync(dirname) {
  if (fs.existsSync(dirname)) {
    return true;
  } else {
    if (mkdirsSync(path.dirname(dirname))) {
      fs.mkdirSync(dirname);
      return true;
    }
  }
}
exports.uploadFile = async (ctx) => {
  return new Promise((resolve, reject) => {
    let form = new formidable.IncomingForm();
    form.encoding = 'utf-8';
    form.keepExtensions = true; // 保留后缀
    form.maxFieldsSize = 2 * 1024 * 1024; // 文件大小2M
    form.multiples = true;
    form.uploadDir = path.join(config.root, config.appPath, config.tempUploads);
    mkdirsSync(form.uploadDir);
    form.parse(ctx.req, (err, fields, files) => {
      if (err) {
        reject(err);
      }
      let data = JSON.parse(fields.data);
      if (files.uploadFile === undefined && data.poster !== '') {
        return resolve({
          fields: data,
          filePath: data.poster
        });
      }
      let filePath = '';

      // 如果提交文件的form中将上传文件的input名设置为uploadFile,就从uploadFile中取上传文件。否则取for in循环第一个上传的文件。
      if (files.uploadFile) {
        filePath = files.uploadFile.path;
      } else {
        for (let key in files) {
          if (files[key].path && filePath === '') {
            filePath = files[key].path;
            break;
          }
        }
      }
      // 文件移动的目录文件夹,不存在时创建目标文件夹
      let dirName = moment().format('YYYYMMDD');
      let targetDir = path.join(config.root, config.appPath, config.uploads, dirName);
      mkdirsSync(targetDir);

      // 以当前时间戳对上传文件进行重命名
      let fileExt = filePath.substring(filePath.lastIndexOf('.'));
      let fileName = new Date().getTime() + fileExt;
      let targetFile = path.join(targetDir, fileName);

      // 移动文件
      fs.rename(filePath, targetFile, (err) => {
        if (err) {
          reject(err);
        } else {
          //上传成功,返回文件的相对路径
          return resolve({
            fields: data,
            filePath: path.join(path.sep, config.uploads, dirName, fileName)
          });
        }
      });
    });
    ctx.session.fileUploadProgress = 0;
    form.on('progress', (bytesReceived, bytesExpected) => {
      // 百分比
      let percent = Math.round((bytesReceived / bytesExpected) * 100);
      console.log('precent', percent + '%');
      ctx.session.fileUploadProgress = percent;
    });
    form.on('end', () => {
      ctx.session.fileUploadProgress = 100 + '%';
    });
  });
};
  • 装载中间件
// 装载
app.use(bodyParser());
app.use(koaJson());
app.use(resource(path.join(path.normalize(__dirname), 'static')));
app.use(router.routes()).use(router.allowedMethods());
app.listen(1112, () => {
  console.log('listen,1112');
});

特别注意在使用 ctx.session 的时候,一定先要装载 session 的中间件

前端上传图片

<div>
  <img :src="imgSrc" alt="" />
  <p>{{msg}}</p>
  <div class="custom" @click="addFile">上传[自定义]</div>
  <div class="custom" @click="deleteFile">取消上传[自定义]</div>
  <p>type="file"的按钮可以隐藏掉</p>
  <input type="file" ref="file" accept="image/png,image/jpeg" @change="fileChanged" />
  <button @click="confirm">确认上传</button>
</div>

这里面有一个小技巧,点击自定义的按钮,触发 type='file'的事件:this.$refs.file.click()

methods:{
    fileChanged() {
      const newFile = this.$refs.file.files[0];
      if (
        newFile.type.indexOf('image/png') === -1 &&
        newFile.type.indexOf('image/jpeg') === -1
      ) {
        this.$refs.file.value = '';
        alert("只接受png和jpeg的图片")
        return;
      }
      if (newFile.size > this.maxSize * 1024) {
        alert(`上传图片最大不能超过${this.maxSize}kb`)
        this.$refs.file.value = '';
        return;
      }
      if (this.file.name !== newFile.name || this.file.size !== newFile.size) {
        // 将图片文件转成BASE64格式
        this.html5Reader(newFile);
      }
      this.$refs.file.value = '';
    },
    html5Reader(file) {
      const reader = new FileReader();
      reader.onload = e => {
        this.imgSrc = e.target.result;
        let image = new Image();
        image.onload = () => {
          let width = image.width;
          let height = image.height;
          if (width / height >= 1.8 && width / height <= 2.2) {
            this.file = file;
          } else {
            alert(`上传图片的宽/高比要求在1.8-2.2之间`)
            this.imgSrc = '';
            this.$refs.file.value = '';
          }
        };
        image.src = e.target.result;
      };
      reader.readAsDataURL(file);
    },
    confirm() {
      let laboratory = {};
      laboratory['poster'] = this.imgSrc;
      // 创建from表单
      let formData = new FormData();
      formData.append('uploadFile', this.file);
      formData.append('data', JSON.stringify(laboratory));
      // 定义接口:需要代理
      const url = "/api/upload"
      // 定义header头
      let config = {
        headers: {
          'Content-Type': 'multipart/form-data'
        }
      };
      // 把请求时间加长
      axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
      axios.defaults.timeout = 20000;
      // 请求
      axios.post(url, formData, config).then((res) => {
        this.msg = `http://127.0.0.1:1112${res.data.message}`
      }, (err) => {
      })
    }
}
{
  proxyTable: {
    '/api': {
      target: "http://127.0.0.1:1112",
      changeOrigin: true,
      pathRewrite: {
        '^/api': ""
      }
    }
  }
}

在使用前端请求接口前,做两件事:1、设置 Content-Type = 'multipart/form-data' 2、代理接口

暂无评论