利用Decorator如何控制Koa路由详解


Posted in Javascript onJune 26, 2018

前言

在Spring中Controller长这样

@Controller
public class HelloController{
 @RequestMapping("/hello")
 String hello() {
 return "Hello World"; 
 }
}

还有Python上的Flask框架

@app.route("/hello")
def hello():
 return "Hello World"

两者都用decorator来控制路由,这样写的好处是更简洁、更优雅、更清晰。

反观Express或Koa上的路由

router.get('/hello', async ctx => {
 ctx.body = 'Hello World'
})

完全差了一个档次

JS从ES6开始就有Decorator了,只是浏览器和Node都还没有支持。需要用babel-plugin-transform-decorators-legacy转义。

Decorator基本原理

首先需要明确两个概念:

  • Decorator只能作用于类或类的方法上
  • 如果一个类和类的方法都是用了Decorator,类方法的Decorator优先于类的Decorator执行

Decorator基本原理:

@Controller
class Hello{

}

// 等同于

Controller(Hello)

Controller是个普通函数,target为修饰的类或方法

// Decorator不传参
function Controller(target) {

}

// Decorator传参
function Controller(params) {
 return function (target) {

 }
}

如果Decorator是传参的,即使params有默认值,在调用时必须带上括号,即:

@Controller()
class Hello{

}

如何在Koa中使用Decorator

我们可以对koa-router中间件进行包装

先回顾一下koa-router基本使用方法:

var Koa = require('koa');
var Router = require('koa-router');

var app = new Koa();
var router = new Router();

router.get('/', async (ctx, next) => {
 // ctx.router available
});

app
 .use(router.routes())
 .use(router.allowedMethods());

再想象一下最终目标

@Controller({prefix: '/hello'})
class HelloController{
 @Request({url: '/', method: RequestMethod.GET})
 async hello(ctx) {
 ctx.body = 'Hello World'
 }
}

类内部方法的装饰器是优先执行的,我们需要对方法重新定义

function Request({url, method}) {
 return function (target, name, descriptor) {
 let fn = descriptor.value
 descriptor.value = (router) => {
  router[method](url, async(ctx, next) => {
  await fn(ctx, next)
  })
 }
 }
}

对RequestMethod进行格式统一

const RequestMethod = {
 GET: 'get',
 POST: 'post',
 PUT: 'put',
 DELETE: 'delete'
}

Controller装饰器需将Request方法添加到Router实例并返回Router实例

import KoaRouter from 'koa-router'

function Controller({prefix}) {
 let router = new KoaRouter()
 if (prefix) {
 router.prefix(prefix)
 }
 return function (target) {
 let reqList = Object.getOwnPropertyDescriptors(target.prototype)
 for (let v in reqList) {
  // 排除类的构造方法
  if (v !== 'constructor') {
  let fn = reqList[v].value
  fn(router)
  }
 }
 return router
 }
}

至此,装饰器基本功能就完成了,基本使用方法为:

import {Controller, Request, RequestMethod} from './decorator'

@Controller({prefix: '/hello'})
export default class HelloController{
 @Request({url: '/', method: RequestMethod.GET})
 async hello(ctx) {
 ctx.body = 'Hello World'
 }
}

在App实例中同路由一样use即可。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
extjs 04_grid 单击事件新发现
Nov 27 Javascript
js/ajax跨越访问-jsonp的原理和实例(javascript和jquery实现代码)
Dec 27 Javascript
js实现适用于素材网站的黑色多级菜单导航条效果
Aug 24 Javascript
jquery实现简单的表单验证
Nov 17 Javascript
jQuery Validate表单验证入门学习
Dec 18 Javascript
基于JS实现textarea中获取动态剩余字数的方法
May 25 Javascript
微信小程序 绘图之饼图实现
Oct 24 Javascript
解决Node.js使用MySQL出现connect ECONNREFUSED 127.0.0.1:3306的问题
Mar 09 Javascript
React.js中常用的ES6写法总结(推荐)
May 09 Javascript
jQuery实现的文字逐行向上间歇滚动效果示例
Sep 06 jQuery
微信小程序实现手指触摸画板
Jul 09 Javascript
jQuery实现的监听导航滚动置顶状态功能示例
Jul 23 jQuery
vue实现点击关注后及时更新列表功能
Jun 26 #Javascript
微信小程序项目总结之点赞 删除列表 分享功能
Jun 25 #Javascript
nuxt.js 缓存实践
Jun 25 #Javascript
vue2.0使用v-for循环制作多级嵌套菜单栏
Jun 25 #Javascript
浅谈super-vuex使用体验
Jun 25 #Javascript
使用vue-router beforEach实现判断用户登录跳转路由筛选功能
Jun 25 #Javascript
使用vue的transition完成滑动过渡的示例代码
Jun 25 #Javascript
You might like
ThinkPHP的RBAC(基于角色权限控制)深入解析
2013/06/17 PHP
php 启动时报错的简单解决方法
2014/01/27 PHP
php中函数前加&符号的作用分解
2014/07/08 PHP
PHP下载远程文件到本地存储的方法
2015/03/24 PHP
PHP 将数组打乱 shuffle函数的用法及简单实例
2016/06/17 PHP
快速保存网页中所有图片的方法
2006/06/23 Javascript
图片动画横条广告带上下滚动可自定义图片、链接等等
2013/10/20 Javascript
jquery复选框多选赋值给文本框的方法
2015/01/27 Javascript
jQuery简单实现页面元素置顶时悬浮效果示例
2016/08/01 Javascript
JavaScript实现使用Canvas绘制图形的基本教程
2016/10/27 Javascript
浅谈layer的iframe弹窗给里面的标签赋值的问题
2016/11/10 Javascript
ajax接收后台数据在html页面显示
2017/02/19 Javascript
js前端实现图片懒加载(lazyload)的两种方式
2017/04/24 Javascript
微信小程序用户自定义模版用法实例分析
2017/11/28 Javascript
通过fastclick源码分析彻底解决tap“点透”
2017/12/24 Javascript
three.js实现炫酷的全景3D重力感应
2018/12/30 Javascript
JavaScript事件对象深入详解
2018/12/30 Javascript
分享JS表单验证源码(带错误提示及密码等级)
2020/01/05 Javascript
如何通过vscode运行调试javascript代码
2020/07/24 Javascript
[37:45]完美世界DOTA2联赛PWL S3 LBZS vs Phoenix 第二场 12.09
2020/12/11 DOTA
常见的python正则用法实例讲解
2016/06/21 Python
详解Python的collections模块中的deque双端队列结构
2016/07/07 Python
Python调用系统底层API播放wav文件的方法
2017/08/11 Python
python调用staf自动化框架的方法
2018/12/26 Python
如何在Django中添加没有微秒的 DateTimeField 属性详解
2019/01/30 Python
tensorflow之并行读入数据详解
2020/02/05 Python
Python阶乘求和的代码详解
2020/02/14 Python
Python多线程获取返回值代码实例
2020/02/17 Python
如何理解Python中包的引入
2020/05/29 Python
Pycharm添加虚拟解释器报错问题解决方案
2020/10/13 Python
HTML5不支持frameset的两种解决方法
2016/11/14 HTML / CSS
上海方立数码笔试题
2013/10/18 面试题
大学本科毕业生求职信范文
2013/12/18 职场文书
保险内勤岗位职责
2014/04/05 职场文书
乡村教师党员四风问题对照检查材料思想汇报
2014/10/08 职场文书
2015年国庆节慰问信
2015/03/23 职场文书