Koa实用技巧

1,397 阅读2分钟

Koa跨域

// koa cors跨域
const cors = require('koa2-cors');
app.use(cors())

Koa文件上传

npm i koa-multer -S

const multer = require('koa-multer');
const { join } = require('path');

const storage = multer.diskStorage({
  // 存储位置
  destination: join(process.cwd(), './public/upload'),
  // 文件名
  filename(req, file, cd){
    // const filename = file.originalname.split('.');
    // cd(null, `${Date.now()}.${filename[filename.length-1]}`)
    cd(null, `${Date.now()}_${file.originalname}`);
  }
})

const upload = multer({storage});
router.post('/upload', upload.single("file"), ctx => {
  console.log(ctx.req.file); // 注意数据存储在原始请求中
  console.log(JSON.stringify(ctx.request.body));
  ctx.body = {
    ok: '上传成功',
    data: {
      message: '文件上传成功'
    }
  }
})

除了koa-multer,还可以使用中间件koa-better-body处理文件上传以及表单处理

Koa错误处理

app.use(async (ctx,next) => {
  try {
    await next();
  } catch(error) {
    // 响应用户
    ctx.status = error.statusCode || error.status || 500;
    ctx.body = error.message;
    // 触发应用层级错误事件
    ctx.app.emit('error', error, ctx);
    console.log('捕获到错误: ', error.message);
  }
})

app.on('error', async ctx => {
  console.error('app 错误:', error.message);

  // 再向上级抛出错误,会停止程序
  // throw error;

})

Koa校验

const bouncer = require('koa-bouncer');
app.use(bouncer.middleware());

/**
 * 定义校验规则
 */
const bouncer = require('koa-bouncer');
const val = async (ctx, next) => {
  try{
    // 自定义校验规则 
    const isUser = name => name === 'abcabc';
    // 校验开始
    ctx.validateBody('name')
    .required('要求提供用户名')
    .isString()
    .trim()
    .isLength(6, 16, '用户名长度为6~16位')
    .check(isUser(ctx.vals.name),'Check Ok');

    // 校验通过,放行
    next();
  } catch(error) {
    if(error instanceof bouncer.ValidationError){
      ctx.body = '校验失败' + error.message;
      return;
    }
    throw error;
  }
}

/**
 * 使用koa-bouncer校验表单
 */
router.post('/', val, ctx => {
  console.log('post /users');
  const { body: user } = ctx.request; // 请求body
  user.id = users.length+1;
  users.push(user);
  ctx.body = { ok: 1 };
    
});

const bouncer = require('koa-bouncer');

router.post('/', async ctx => {
  try{
    // 输入验证码
    const { code, to, expires } = ctx.session.smsCode;
    ctx.validateBody('phone')
    .required('必须提供手机号码')
    .isString()
    .trim()
    .match(/1[3-9]\d{9}/, '手机号码不合法')
    .eq(to, '请填写接收短信的手机号码');

    ctx.validateBody('code')
    .required('必须填写短信验证码')
    .isString()
    .trim()
    .isLength(6, 6, '必须是6位验证码')
    .eq(code, '验证码填写错误')
    .checkPred(() => new Date() - new Date(expires) < 0, '验证码已过期');

    ctx.validateBody('password')
    .required('必须提供密码')
    .isString()
    .trim()
    .match(/[a-zA-Z0-9]{6,16}/, '密码不合法');

    // 入库,略
    ctx.body = { ok: 1 };

  } catch(error) {
    if(error instanceof bouncer.ValidationError){
      console.log(error);
      ctx.status = 401;
    } else {
      ctx.status = 500;
    }
    ctx.body = { ok: 0, message: error.message };
  }
})

Koa验证码

const captcha = require('trek-captcha');

router.get('/captcha', async ctx => {
  console.log('captcha: ', ctx.session.captcha);
  const { token, buffer} = await captcha({size: 4});
  // 一般将生产的验证码存储到session
  ctx.session.captcha = token;
  ctx.body = buffer;
})

定时任务

const schedule = require('node-schedule');
function initSchedule(){
	schedule.scheduleJob('*/3 * * * * *',handler(){
	  console.log('定时任务 三秒执行一次'+ new Date());
	});
}