利用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 相关文章推荐
JS字符串函数扩展代码
Sep 13 Javascript
js限制文本框输入长度两种限制方式(长度、字节数)
Dec 19 Javascript
Jquery插件实现点击获取验证码后60秒内禁止重新获取
Mar 13 Javascript
jQuery实现自定义事件的方法
Apr 17 Javascript
ECMAScript6函数默认参数
Jun 12 Javascript
jQuery根据元素值删除数组元素的方法
Jun 24 Javascript
jquery实现的树形目录实例
Jun 26 Javascript
jquery实现点击查看更多内容控制段落文字展开折叠效果
Aug 06 Javascript
老生常谈 关于JavaScript的类的继承
Jun 24 Javascript
利用prop-types第三方库对组件的props中的变量进行类型检测
May 02 Javascript
JavaScript闭包_动力节点Java学院整理
Jun 27 Javascript
vue实现长图垂直居上 vue实现短图垂直居中
Oct 18 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
Terran剧情介绍
2020/03/14 星际争霸
PHP 截取字符串专题集合
2010/08/19 PHP
PHPWind与Discuz截取字符函数substrs与cutstr性能比较
2011/12/05 PHP
关于Zend Studio 配色方案插件的介绍
2013/06/24 PHP
thinkphp微信开发(消息加密解密)
2015/12/02 PHP
PHP mysql事务问题实例分析
2016/01/18 PHP
Adnroid 微信内置浏览器清除缓存
2016/07/11 PHP
Yii2框架操作数据库的方法分析【以mysql为例】
2019/05/27 PHP
JS 的应用开发初探(mootools)
2009/12/19 Javascript
JQuery切换显示的效果实例代码
2013/02/27 Javascript
jQuery on方法传递参数示例
2014/12/09 Javascript
jquery图片切换实例分析
2015/04/15 Javascript
jquery实现滑屏大图定时收缩为小banner图片的广告代码
2015/09/02 Javascript
基于jquery实现可定制的web在线富文本编辑器附源码下载
2015/11/17 Javascript
Bootstrap3.0建站教程(一)之bootstrap表单元素排版
2016/06/01 Javascript
JS自定义滚动条效果简单实现代码
2020/10/27 Javascript
解决vuecli3.0热更新失效的问题
2018/09/19 Javascript
浅谈vue中关于checkbox数据绑定v-model指令的个人理解
2018/11/14 Javascript
layui数据表格跨行自动合并的例子
2019/09/02 Javascript
layui 上传插件 带预览 非自动上传功能的实例(非常实用)
2019/09/23 Javascript
vue 更改连接后台的api示例
2019/11/11 Javascript
vue-cli+webpack项目打包到服务器后,ttf字体找不到的解决操作
2020/08/28 Javascript
详解js创建对象的几种方式和对象方法
2021/03/01 Javascript
Python遍历文件夹和读写文件的实现方法
2017/05/10 Python
用virtualenv建立多个Python独立虚拟开发环境
2017/07/06 Python
Python实现将照片变成卡通图片的方法【基于opencv】
2018/01/17 Python
numpy.linspace函数具体使用详解
2019/05/27 Python
python实现多进程按序号批量修改文件名的方法示例
2019/12/30 Python
阿里旅行:飞猪
2017/01/05 全球购物
德国家具、照明、家居用品网上商店:Wayfair.de
2020/02/13 全球购物
小学生迎国庆演讲稿
2014/09/05 职场文书
Django程序的优化技巧
2021/04/29 Python
解析Redis Cluster原理
2021/06/21 Redis
SpringBoot整合RabbitMQ的5种模式实战
2021/08/02 Java/Android
Nginx使用Lua模块实现WAF的原理解析
2021/09/04 Servers
使用python将HTML转换为PDF pdfkit包(wkhtmltopdf) 的使用方法
2022/04/21 Python