网创优客建站品牌官网
为成都网站建设公司企业提供高品质网站建设
热线:028-86922220
成都专业网站建设公司

定制建站费用3500元

符合中小企业对网站设计、功能常规化式的企业展示型网站建设

成都品牌网站建设

品牌网站建设费用6000元

本套餐主要针对企业品牌型网站、中高端设计、前端互动体验...

成都商城网站建设

商城网站建设费用8000元

商城网站建设因基本功能的需求不同费用上面也有很大的差别...

成都微信网站建设

手机微信网站建站3000元

手机微信网站开发、微信官网、微信商城网站...

建站知识

当前位置:首页 > 建站知识

node.js的后端路由自动加载怎么实现

这篇文章主要介绍了node.js的后端路由自动加载怎么实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇node.js的后端路由自动加载怎么实现文章都会有所收获,下面我们一起来看看吧。

创新互联公司主打移动网站、成都做网站、成都网站设计、网站改版、网络推广、网站维护、主机域名、等互联网信息服务,为各行业提供服务。在技术实力的保障下,我们为客户承诺稳定,放心的服务,根据网站的内容与功能再决定采用什么样的设计。最后,要实现符合网站需求的内容、功能与设计,我们还会规划稳定安全的技术方案做保障。

背景

我们前端同学或者是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.js的后端路由自动加载怎么实现

2、thinkjs的路由自动加载

控制器文件文件自动加载逻辑

1)、应用初始化,创建实例
....

2)、遍历控制器目录, 加载控制器

得到目录文件对应的导出class的 Map
例如 Controller目录下 他会加载出来模块、控制器、方法挂在他的app上。

node.js的后端路由自动加载怎么实现

{
  '/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,列表去匹配, 如果有就执行。

thinkjs和koa-router路由匹配的区别

1、 think  think-router解析完, think-controller去匹配执行, 他这个是动态匹配。
2、koa-router 匹配到路由后, 自己再用koa-compose组装一个小洋葱圈去执行
! 这种我的理解是程序启动就注册好的顺序image.png

node.js的后端路由自动加载怎么实现

node.js的后端路由自动加载怎么实现

总结: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

关于“node.js的后端路由自动加载怎么实现”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“node.js的后端路由自动加载怎么实现”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注创新互联行业资讯频道。


本文标题:node.js的后端路由自动加载怎么实现
网站路径:http://bjjierui.cn/article/ipsich.html

其他资讯