>  기사  >  웹 프론트엔드  >  노드 백엔드 라우팅의 자동 로딩에 대해 이야기하는 기사

노드 백엔드 라우팅의 자동 로딩에 대해 이야기하는 기사

青灯夜游
青灯夜游앞으로
2023-01-18 20:57:251505검색

노드 백엔드 라우팅의 자동 로딩에 대해 이야기하는 기사

이 기사는 사람들에게 적합합니다

특정 기초를 갖춘 Node.js 개발자有一定基础的Node.js开发人员

难易程度

中等

背景

今天来谈谈node后端中路由的问题。【相关教程推荐:nodejs视频教程

我们前端同学或者是nodejs服务端的同学,在你们使用express和koajs写接口的时候, 咱们是不都要写路由 比如如下

登录接口router.post('/user/login', user.login);

获取用户信息接口router.get('/user/info', checkAuth, user.xxx);

난이도

Medium

Background

오늘은 노드 백엔드의 라우팅 문제에 대해 이야기해 보겠습니다. [추천 관련 튜토리얼: nodejs 동영상 튜토리얼]

프론트엔드 급우 또는 동급생 nodejs 서버, express 및 koajs를 사용하여 인터페이스를 작성할 때 다음과 같은 경로를 작성할 필요가 없습니다.

Login 인터페이스router.post('/user/login', user.login);<p></p> 사용자 정보 가져오기 인터페이스 <code>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个

write 1,000개의 인터페이스를 router.js에 1,000번 등록해야 하나요? 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. 더 품격 있는 글쓰기

공통 경로 자동 로딩

연락을 해보니 여러 가지 방법으로 경로 자동 로딩을 구현하는 프레임워크가 있다는 것을 알게 되었습니다.

1. Think 시리즈

Admin/adList/index

첫 번째는 thinkPHP와 thinkjs, 참조 링크는 노드 백엔드 라우팅의 자동 로딩에 대해 이야기하는 기사thinkjs.org/zh-cn/doc/3…

둘의 관계는 thinkjs와 이후의 thinkPHP에 속합니다. 설계 및 개발되었습니다.

다른 두 경로의 자동 로딩은 파일 기반이므로 컨트롤러 이름과 메서드 이름을 작성한 후 추가 구성 없이 경로에 직접 액세스할 수 있습니다.

1.thinkphp의 경로가 자동으로 로드됩니다

tp가 모듈/컨트롤러/메소드 파일 이름에 따라 자동으로 로드됩니다

module?/controller/Action

예를 들어 아래 Admin 모듈 아래에는 AdlistController.class.php의 index 메소드가 있습니다. 그의 경로는

노드 백엔드 라우팅의 자동 로딩에 대해 이야기하는 기사

2로 자동 로드되고, thinkjs 경로는 자동으로 로드됩니다.

컨트롤러 파일 파일 자동 로딩 로직

1), 애플리케이션 초기화, 인스턴스 생성 控制器匹配部分 是在当请求进来的时候做的事情。

就是当请求进来,会先进过,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

노드 백엔드 라우팅의 자동 로딩에 대해 이야기하는 기사

노드 백엔드 라우팅의 자동 로딩에 대해 이야기하는 기사

总结:thinkjs是先把你的控制器和方法加载出来, 最后当请求进来的时候,利用think-controller 去先匹配模块/控制器,再匹配方法, 如果有的话就帮你执行,没有的话,就404

二、以egg改造版为例 装饰器的路由自动加载

装饰器的写法类似于 java spring中的注解

node框架中 nestjsmidwayjs....

🎜2 ) , 컨트롤러 디렉터리를 탐색하고 컨트롤러를 로드하고 🎜🎜 디렉터리 파일 🎜에 해당하는 내보낸 클래스의 맵을 가져옵니다. 예를 들어 Controller 디렉터리에서 그는 모듈, 컨트롤러 및 메서드를 로드하고 이를 앱에 걸어둘 것입니다. 🎜🎜🎜🎜
{
  '/order': [class default_1 extends default_1],
  '/user': [class default_1 extends default_1]
}
🎜🎜3. 컨트롤러 매칭 부분🎜🎜🎜이전 단계는 thinkjs 애플리케이션의 시작 단계에서 수행되는 작업입니다. 🎜🎜요청이 들어오면 컨트롤러 매칭 부분 단계가 완료됩니다. 🎜🎜즉, 요청이 들어오면 Think-router가 모듈, 컨트롤러, 액션을 구문 분석하여 ctx에 정지시킵니다. 🎜🎜여기서 이 요청의 모듈, 컨트롤러, 액션을 ctx에서 가져와서 시작 시 앱에 걸려 있는 모듈, 컨트롤러, 액션, 목록과 일치시키면 실행하세요. 🎜🎜think-controller의 매칭 로직은 github.com/thinkjs/thi…🎜🎜
🎜thinkjs와 koa-router의 경로 매칭 차이🎜
🎜1. think Think-Router 분석 이후 Think-Controller는 매칭을 수행하는데, 이는 동적 매칭이다. 🎜2.koa-router가 경로를 일치시킨 후 koa-compose를 사용하여 실행을 위한 작은 양파링을 조립할 수 있습니다🎜! 프로그램이 시작될 때 주문이 등록되는 것으로 알고 있습니다.
image.png🎜🎜🎜노드 백엔드 라우팅의 자동 로딩에 대해 이야기하는 기사🎜🎜노드 백엔드 라우팅의 자동 로딩에 대해 이야기하는 기사🎜🎜요약: thinkjs가 컨트롤러와 메소드를 먼저 로드하고 마지막으로 요청이 들어오면 think-controller를 사용하여 먼저 모듈을 일치시킵니다. /controller, 그리고 메소드가 있으면 실행됩니다. 그렇지 않으면 404🎜🎜🎜🎜 2. egg 수정 버전을 예로 들면 데코레이터의 경로는 자동입니다. 데코레이터의 로드🎜🎜🎜🎜🎜 작성 방법은 Java Spring의 주석과 유사합니다. 노드 프레임워크의 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<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 教程

위 내용은 노드 백엔드 라우팅의 자동 로딩에 대해 이야기하는 기사의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 juejin.cn에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제