一文聊聊node後端路由自動加載

青灯夜游
發布: 2023-02-06 20:14:31
轉載
1466 人瀏覽過

一文聊聊node後端路由自動加載

本文適宜人群

#有一定基礎的Node.js開發人員

#難易度

背景

##今天來談談node後端中路由的問題。 【相關教學推薦:

nodejs影片教學

我們前端同學或是nodejs服務端的同學,在你們使用express和koajs寫介面的時候, 咱們是不都要寫路由比如如下

登入介面

router.post('/user/login', user.login);

取得使用者資訊介面

router.get('/ user/info', checkAuth, user.xxx);

這種寫法很常見, 先註冊路由,再指定後續要執行的中間件方法。

可是當接口越來越多,比如有1000個接口, 就得這樣註冊1000次,多了我認為是一件很麻煩且不優雅的事情

koa&express 路由註冊範例

const express = require('express'); const router = express.Router(); const user = require('../../controllers/user'); const tokenCheck = require('../../middleware/token_check_api'); //用户注册 router.post('/user/register', user.register); //用户登录 router.post('/user/login', user.login); router.post('xxx', tokenCheck, user.xxx); ...假装还有有1000个
登入後複製

寫1000個介面就要在router.js裡註冊1000次嗎?

eggjs路由註冊範例

'use strict'; // egg-router extends koa-router import { Application } from 'egg'; export default (app: Application) => { const { router, controller, middleware } = app; router.get('/', middleware.special(), controller.home.index); router.get('/1', middleware.special(), controller.home.index1); .... router.get('/error', controller.home.error); };
登入後複製
**這種專案擴大時候, 我認為這種設定會顯得很冗餘,所以就需要實作一種路由自動載入的機制來改善它優化它。

1、提升效率

2、更優雅的寫作

常見的路由自動載入

接觸下來,我發現有幾個框架用不同方法實現了路由自動載入。

一、think系列

第一個是thinkPHP和thinkjs, 參考連結

thinkjs.org/zh-cn/doc /3…

他兩的關係屬於是thinkjs是後來依照thinkPHP的想法設計開發的。

他兩路由自動載入屬於基於檔案的, 就是說你按控制器的名字和方法名寫好,直接就可以存取路由,不需要額外的設定。

1、thinkphp的路由自動載入

tp是按模組/控制器/方法檔案名稱自動載入

module?/controller/Action
登入後複製
比方下面這個Admin模組下, AdlistController.class.php裡index方法 他的路由就會自動載入為

Admin/adList/index

一文聊聊node後端路由自動加載

#2、thinkjs的路由自動載入

控制器檔案檔案自動載入邏輯

1)、套用初始化,建立實例

....

2)、遍歷控制器目錄, 載入控制器

得到目錄檔案對應的匯出class的Map

例如Controller目錄下 他會載入出來模組、控制器、方法掛在他的app上。

一文聊聊node後端路由自動加載

{ '/order': [class default_1 extends default_1], '/user': [class default_1 extends default_1] }
登入後複製

3、控制器匹配部分

#上一步是在thinkjs應用程式啟動階段做的事情。

這一步

控制器匹配部分是在當請求進來的時候做的事情。

就是當請求進來,會先進過,think-router 把module, controller, action ,解析出來掛在ctx上。

在這裡拿ctx上本次請求的module, controller, action去和啟動時掛在app的 module, controller, action,列表去匹配, 如果有就執行。

think-controller的匹配邏輯詳見

github.com/thinkjs/thi…

thinkjs和koa-router路由匹配的區別
1、 think think-router解析完, think-controller去匹配執行, 他這個是動態匹配。

2、koa-router 配對到路由後, 自己再用koa-compose組裝一個小洋蔥圈去執行
! 這種我的理解是程式啟動就註冊好的順序
image.png

一文聊聊node後端路由自動加載

一文聊聊node後端路由自動加載

總結:thinkjs是先把你的控制器和方法載入出來, 最後當請求進來的時候,利用

think-controller去先匹配模組/控制器,再匹配方法, 如果有的話就幫你執行,沒有的話,就404

二、以egg改造版為例裝飾器的路由自動載入

裝飾器的寫法類似於java spring中的註解

node框架中

nestjsmidwayjs已經全面擁抱了裝飾器路由。

  • 写法比较优雅
  • 建议控制器的文件名和控制器名字保持一致, 这样你找api也比较好找 比如控制的文件名字叫home.ts, 那你控制器注册也写@controller('/home')来保持一致。

1、 控制器装饰器 @controller('/order')

'use strict'; import { Context } from 'egg'; import BaseController from './base'; import { formatDate } from '~/app/lib/utils'; import { SelfController, Get } from './../router' @SelfController('/home') export default class HomeController extends BaseController { [x: string]: any; @validate() @Get("/") public async index(): Promise {} }
登入後複製

2、方法装饰器 @Get('/export')、 @Post('/list')

get接口 就是@Get()

post的接口 就是@Post()

@Get("/") public async index(): Promise {} @Post("/update") public async update(): Promise {}
登入後複製

3、装饰器路由统一注册

这里统一按egg的方法循环注册路由

'use strict'; import { Application, Context } from 'egg'; import 'reflect-metadata'; const CONTROLLER_PREFIX: string = ''; const methodMap: Map = new Map(); const rootApiPath: string = ''; interface CurController { pathName: string; fullPath: string; } /** * controller 装饰器,设置api公共前缀 * @param pathPrefix {string} * @constructor */ export const SelfController = (pathPrefix?: string): ClassDecorator => (targetClass): void => { // 在controller上定义pathPrefix的元数据 // https://github.com/rbuckton/reflect-metadata (Reflect as any).defineMetadata(CONTROLLER_PREFIX, pathPrefix, targetClass); }; const methodWrap = (path: string, requestMethod: string): MethodDecorator => (target, methodName): void => { // 路由装饰器参数为空时,路由为方法名 const key = path ? `${requestMethod}·${path}·${String(methodName)}` : `${requestMethod}·${String(methodName)}·/${String(methodName)}`; methodMap.set(key, target); }; // Post 请求 export const Post = (path: string = ''): MethodDecorator => methodWrap(path, 'post'); // Get 请求 export const Get = (path: string = ''): MethodDecorator => methodWrap(path, 'get'); export default (app: Application): void => { const { router } = app; // 遍历methodMap, 注册路由 methodMap.forEach((curController: CurController, configString: string) => { // 请求方法, 请求路径, 方法名 const [ requestMethod, path, methodName ] = configString.split(`·`); // 获取controller装饰器设置的公共前缀 // 如果controller没有添加SelfController装饰器,则取文件名作为路径 let controllerPrefix: string | undefined | null = (Reflect as any).getMetadata(CONTROLLER_PREFIX, curController.constructor); if (!(Reflect as any).hasMetadata(CONTROLLER_PREFIX, curController.constructor)) { controllerPrefix = `/${curController.pathName.split(`.`).reverse()[0]}`; } const func: (this: Context, ...args: any[]) => Promise = async function (...args: any[]): Promise { return new (curController.constructor as any)(this)[methodName](...args); }; // 注册路由 router[requestMethod](rootApiPath + controllerPrefix + path, func); }); };
登入後複製

建议使用node写服务直接上midwayjs或者nestjs

总结

通过如上比较,相信你对think系列框架堵文件的路由自动加载和装饰器的路由加载,有了一定了解,他们的这种设计思想值得学习吧, 希望对你有所启发。

还有我认为装饰器的路由写起来,比较优雅, 不知道各位小伙伴怎么看,评论区说说?

更多node相关知识,请访问:nodejs 教程

以上是一文聊聊node後端路由自動加載的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:juejin.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!