您好,登錄后才能下訂單哦!
這篇文章主要介紹了node.js的后端路由自動加載怎么實現(xiàn)的相關(guān)知識,內(nèi)容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇node.js的后端路由自動加載怎么實現(xiàn)文章都會有所收獲,下面我們一起來看看吧。
我們前端同學(xué)或者是nodejs服務(wù)端的同學(xué),在你們使用express和koajs寫接口的時候, 咱們是不都要寫路由 比如如下
登錄接口router.post('/user/login', user.login);
獲取用戶信息接口router.get('/user/info', checkAuth, user.xxx);
這種寫法很常見, 先注冊路由,再指定后續(xù)要執(zhí)行的中間件方法。
可是當(dāng)接口越來越多,比如有1000個接口, 就得這樣注冊1000次,多了我認為是一件很麻煩且不優(yōu)雅的事情
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); };
**這種項目擴大時候, 我認為這種配置會顯得很冗余,所以就需要實現(xiàn)一種路由自動加載的機制來改善它優(yōu)化它。
1、提升效率
2、更優(yōu)雅的編寫
接觸下來, 我發(fā)現(xiàn)有幾個框架用不同方法實現(xiàn)了路由自動加載。
一、think系列
第一個是thinkPHP和thinkjs, 參考鏈接 thinkjs.org/zh-cn/doc/3…
他兩的關(guān)系屬于是thinkjs是后來按照thinkPHP的思想設(shè)計開發(fā)的。
他兩路由自動加載屬于基于文件的, 就是說你按控制器的名字和方法名寫好,直接就可以訪問路由,不需要額外的配置。
1、thinkphp的路由自動加載
tp是 按模塊/控制器/方法文件名 自動加載
module?/controller/Action
比方下面這個Admin模塊下, AdlistController.class.php里 index方法
他的路由就會自動加載為 Admin/adList/index
2、thinkjs的路由自動加載
控制器文件文件自動加載邏輯
1)、應(yīng)用初始化,創(chuàng)建實例
....
2)、遍歷控制器目錄, 加載控制器
得到目錄文件對應(yīng)的導(dǎo)出class的 Map
例如 Controller目錄下
他會加載出來模塊、控制器、方法掛在他的app上。
{ '/order': [class default_1 extends default_1], '/user': [class default_1 extends default_1] }
3、控制器匹配部分
上一步是在thinkjs應(yīng)用啟動階段做的事情。
這一步 控制器匹配部分
是在當(dāng)請求進來的時候做的事情。
就是當(dāng)請求進來,會先進過,think-router 把module, controller, action ,解析出來掛在ctx上。
在這里拿ctx上本次請求的module, controller, action去和啟動時掛在app的 module, controller, action,列表去匹配, 如果有就執(zhí)行。
1、 think think-router解析完, think-controller去匹配執(zhí)行, 他這個是動態(tài)匹配。
2、koa-router 匹配到路由后, 自己再用koa-compose組裝一個小洋蔥圈去執(zhí)行
! 這種我的理解是程序啟動就注冊好的順序image.png
總結(jié):thinkjs是先把你的控制器和方法加載出來, 最后當(dāng)請求進來的時候,利用think-controller
去先匹配模塊/控制器,再匹配方法, 如果有的話就幫你執(zhí)行,沒有的話,就404
二、以egg改造版為例 裝飾器的路由自動加載
裝飾器的寫法類似于 java spring中的注解
node框架中 nestjs
和midwayjs
已經(jīng)全面擁抱了裝飾器路由。
寫法比較優(yōu)雅
建議控制器的文件名和控制器名字保持一致, 這樣你找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<void> {} }
2、方法裝飾器 @Get('/export')、 @Post('/list')
get接口 就是 @Get()
post的接口 就是 @Post()
@Get("/") public async index(): Promise<void> {} @Post("/update") public async update(): Promise<void> {}
3、裝飾器路由統(tǒng)一注冊
這里統(tǒng)一按egg的方法循環(huán)注冊路由
'use strict'; import { Application, Context } from 'egg'; import 'reflect-metadata'; const CONTROLLER_PREFIX: string = ''; const methodMap: Map<string, any> = new Map<string, any>(); const rootApiPath: string = ''; interface CurController { pathName: string; fullPath: string; } /** * controller 裝飾器,設(shè)置api公共前綴 * @param pathPrefix {string} * @constructor */ export const SelfController = (pathPrefix?: string): ClassDecorator => (targetClass): void => { // 在controller上定義pathPrefix的元數(shù)據(jù) // https://github.com/rbuckton/reflect-metadata (Reflect as any).defineMetadata(CONTROLLER_PREFIX, pathPrefix, targetClass); }; const methodWrap = (path: string, requestMethod: string): MethodDecorator => (target, methodName): void => { // 路由裝飾器參數(shù)為空時,路由為方法名 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裝飾器設(shè)置的公共前綴 // 如果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<any> = async function (...args: any[]): Promise<any> { return new (curController.constructor as any)(this)[methodName](...args); }; // 注冊路由 router[requestMethod](rootApiPath + controllerPrefix + path, func); }); };
建議使用node寫服務(wù)直接上midwayjs或者nestjs
關(guān)于“node.js的后端路由自動加載怎么實現(xiàn)”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對“node.js的后端路由自動加載怎么實現(xiàn)”知識都有一定的了解,大家如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。