Node.js developers with a certain foundation
Medium
Today let’s talk about routing issues in the node backend . [Related tutorial recommendations: nodejs video tutorial]
Our front-end students or nodejs server students, when you use express and koajs to write interfaces, we don’t have to write routes, for example As follows
Login interfacerouter.post('/user/login', user.login);
Get user information interfacerouter.get('/ user/info', checkAuth, user.xxx);
This way of writing is very common. Register the route first, and then specify the middleware method to be executed later.
But when there are more and more interfaces, for example, 1,000 interfaces, you have to register like this 1,000 times. I think it is a very troublesome and inelegant thing if there are more interfaces.
koa&express routing registration example
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个
Does it require registering 1,000 times in router.js when writing 1,000 interfaces?
eggjs route registration example
'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); };
**When this kind of project expands, I think this configuration will appear very redundant, so it is necessary to implement a route automatic loading mechanism. To improve it and optimize it.
1. Improve efficiency
2. Write more elegantly
After contacting it, I found Several frameworks implement route autoloading in different ways.
1. think series
The first one is thinkPHP and thinkjs, reference linkthinkjs.org/zh-cn/doc /3…
The relationship between the two is that thinkjs was later designed and developed according to the ideas of thinkPHP.
The automatic loading of the other two routes is file-based, which means that after you write the controller name and method name, you can access the route directly without additional configuration.
1. Thinkphp’s routing is automatically loaded
tp is automatically loaded according to the module/controller/method file name
module?/controller/Action
For example, the following Admin module Next, the index method in AdlistController.class.php
His route will be automatically loaded as Admin/adList/index
##2. Thinkjs’ route will be automatically loaded as
Controller file automatic loading logic1), application initialization, create instance....
For example, in the Controller directory
He will load modules, controllers, and methods and hang them on his app.
{ '/order': [class default_1 extends default_1], '/user': [class default_1 extends default_1] }
3. Controller matching part
The previous step is done during the startup phase of the thinkjs application. This stepThe controller matching part is what is done when the request comes in.
2. After koa-router matches the route, you can use koa-compose to assemble a small onion ring to execute
! My understanding is that the sequence is registered when the program starts
image.png
think-controller First match the module/controller, and then match the method. If there is one, it will be executed for you. If not, it will be 404
2. Use egg The modified version takes the decorator route as an example to automatically load
The writing method of the decorator is similar to the annotations in java spring
in the node frameworknestjs and
midwayjs have fully embraced decorator routing.
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、装饰器路由统一注册
这里统一按egg的方法循环注册路由
'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 装饰器,设置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<any> = async function (...args: any[]): Promise<any> { return new (curController.constructor as any)(this)[methodName](...args); }; // 注册路由 router[requestMethod](rootApiPath + controllerPrefix + path, func); }); };
建议使用node写服务直接上midwayjs或者nestjs
通过如上比较,相信你对think系列框架堵文件的路由自动加载和装饰器的路由加载,有了一定了解, 他们的这种设计思想值得学习吧
, 希望对你有所启发。
还有我认为装饰器的路由写起来,比较优雅, 不知道各位小伙伴怎么看,评论区说说?
更多node相关知识,请访问:nodejs 教程!
The above is the detailed content of An article to talk about the automatic loading of node back-end routing. For more information, please follow other related articles on the PHP Chinese website!