利用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 相关文章推荐
escape、encodeURI 和 encodeURIComponent 的区别
Mar 02 Javascript
javaScript parseInt字符转化为数字函数使用小结
Nov 05 Javascript
jQuery下拉框的简单应用
Jun 24 Javascript
详解Vue.js——60分钟组件快速入门(上篇)
Dec 05 Javascript
JS运动改变单物体透明度的方法分析
Jan 23 Javascript
angularjs实现table增加tr的方法
Feb 27 Javascript
vue父组件向子组件传递多个数据的实例
Mar 01 Javascript
微信小程序url传参写变量的方法
Aug 09 Javascript
angular6 利用 ngContentOutlet 实现组件位置交换(重排)
Nov 02 Javascript
策略模式实现 Vue 动态表单验证的方法
Sep 16 Javascript
vue获取form表单的值示例
Oct 29 Javascript
vue组件开发之tab切换组件使用详解
Aug 21 Javascript
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
php smarty模版引擎中的缓存应用
2009/12/02 PHP
phpMyAdmin链接MySql错误 个人解决方案
2009/12/28 PHP
PHP 读取大文件的X行到Y行内容的实现代码
2013/06/24 PHP
window.showModalDialog使用手册
2007/01/11 Javascript
十分钟打造AutoComplete自动完成效果代码
2009/12/26 Javascript
JavaScript 未结束的字符串常量常见解决方法
2010/01/24 Javascript
JavaScript 学习历程和心得分享
2010/12/12 Javascript
对Jquery中的ajax再封装,简化操作示例
2014/02/12 Javascript
jquery的ajax简单结构示例代码
2014/02/17 Javascript
node.js中的fs.fchmodSync方法使用说明
2014/12/16 Javascript
JavaScript 七大技巧(一)
2015/12/13 Javascript
js实现分割上传大文件
2016/03/09 Javascript
浅谈JS正则表达式的RegExp对象和括号的使用
2016/07/28 Javascript
mongoose中利用populate处理嵌套的方法
2017/05/26 Javascript
webpack项目调试以及独立打包配置文件的方法
2018/02/28 Javascript
JS中原始值和引用值的储存方式示例详解
2018/03/23 Javascript
详解Node使用Puppeteer完成一次复杂的爬虫
2018/04/18 Javascript
js字符串处理之绝妙的代码
2019/04/05 Javascript
Vue中实现权限控制的方法示例
2019/06/07 Javascript
VUE实时监听元素距离顶部高度的操作
2020/07/29 Javascript
vue项目打包后提交到git上为什么没有dist这个文件的解决方法
2020/09/16 Javascript
[04:52]第二届DOTA2亚洲邀请赛主赛事第一天比赛集锦:OG娜迦海妖放大配合谜团大中3人
2017/04/02 DOTA
python算法学习之桶排序算法实例(分块排序)
2013/12/18 Python
Python实现将SQLite中的数据直接输出为CVS的方法示例
2017/07/13 Python
Scrapy的简单使用教程
2017/10/24 Python
基于Pandas读取csv文件Error的总结
2018/06/15 Python
python实现字符串中字符分类及个数统计
2018/09/28 Python
浅谈python中拼接路径os.path.join斜杠的问题
2018/10/23 Python
如何使用python记录室友的抖音在线时间
2020/06/29 Python
python实现简单文件读写函数
2021/02/25 Python
使用phonegap进行本地存储的实现方法
2017/03/31 HTML / CSS
使用html5新特性轻松监听任何App自带返回键的示例
2018/03/13 HTML / CSS
软件部经理岗位职责范本
2014/02/25 职场文书
竞争与合作演讲稿
2014/05/12 职场文书
为了顺利买到演唱会的票用Python制作了自动抢票的脚本
2021/10/16 Python
JavaScript 原型与原型链详情
2021/11/02 Javascript