有勇气的牛排博客

Typescript Express 03 框架 装饰器 路由注册 登录验证

有勇气的牛排 338 TypeScript 2024-11-24 00:12:11

1 装饰器路由注册

Express 框架可以支持装饰器,但它本身并未原生提供装饰器功能。要在 Express 中使用装饰器功能,通常需要借助 TypeScript 和第三方库(如 reflect-metadataclass-transformer)来实现。这种方式适合构建更加结构化、模块化的应用程序,尤其是在大型项目中。

1. 安装

# 安装用于验证和转换的库 npm install class-validator class-transformer

1.2 配置 tsconfig.json

{ "esModuleInterop": true, "allowSyntheticDefaultImports": true, "compilerOptions": { "target": "ES6", "module": "commonjs", "rootDir": "./src", "outDir": "./dist", "strict": true, "esModuleInterop": true, // 启用装饰器支持 "experimentalDecorators": true, "emitDecoratorMetadata": true }, "include": [ "src" ] }

1.3 路由装饰器util 支持async

``src/utils/route.decorator.ts

import { Router, Request, Response, NextFunction } from 'express'; // 全局路由对象 const router = Router(); /** * 路由装饰器 * @param method 请求方法 ('get', 'post', 'put', 'delete') * @param path 路由路径 */ export function Route(method: 'get' | 'post' | 'put' | 'delete', path: string) { return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; // 包装异步函数,处理错误 descriptor.value = async (req: Request, res: Response, next: NextFunction) => { try { await originalMethod(req, res, next); } catch (error) { next(error); // 将错误交给 Express 的错误处理中间件 } }; // 将路由注册到全局 router 对象 router[method](path, descriptor.value); }; } // 导出全局 router export { router };

1.4 路由案例

DecoratorController.ts

import { Request, Response } from 'express'; import { Route } from '../utils/route.decorator'; import ResponseUtil from "../utils/ResponseUtil"; export class DecoratorController { // http://127.0.0.1:3000/api/v1/user2/2 @Route('get', '/user2/:id') async getUserById(req: Request, res: Response) { const { id } = req.params; // 从动态路由中提取参数 const data = { id }; // 假设这里是异步数据库查询操作 await new Promise((resolve) => setTimeout(resolve, 100)); ResponseUtil.success(res, data, '查询成功', 20000); } }

1.5 注册

server.ts

// 装饰器路由注册 import './controller_decorator/DecoratorController'; // 确保装饰器逻辑生效 import { router } from './utils/route.decorator'; app.use('/api/v1', router);

image.png

2 装饰器 登录验证

2.1 定义登录验证装饰器

创建一个装饰器 @Auth,用于检查请求头中是否包含有效的 token。可以结合业务逻辑验证 token,例如解码、检查过期等。

``src/filter/auth.ts

import { Request, Response, NextFunction } from 'express'; /** * Auth 装饰器:验证请求头中的 token * @param validateTokenFunction 自定义的 token 验证逻辑 */ export function Auth(validateTokenFunction: (token: string) => boolean) { return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; // 包装原始方法,添加 token 验证逻辑 descriptor.value = async (req: Request, res: Response, next: NextFunction) => { // const authorization = req.headers['authorization']?.replace('Bearer ', ''); const authorization = req.headers['authorization']; console.log(`authorization: ${authorization}`); if (!authorization || !validateTokenFunction(authorization)) { // 如果 token 无效,返回 401 return res.status(401).json({ code: 401, message: 'Unauthorized: Invalid or missing token', }); } // 验证通过,继续执行原始路由逻辑 await originalMethod(req, res, next); }; }; }

2.2 登录校验

token_util.ts

npm install jsonwebtoken
import jwt from 'jsonwebtoken'; export class TokenUtil { // 用于签名的密钥 private static secret = '123456有勇气的牛排'; // 验证 token 是否有效 实际逻辑根据业务自己补充吧 static validateToken(token: string): boolean { console.log("token验证") return true; // try { // const decoded = jwt.verify(token, this.secret); // console.log('Token is valid:', decoded); // return true; // } catch (err) { // console.error('Invalid token:', err.message); // return false; // } } }

2.3 注册到路由

import { Request, Response } from 'express'; import { Route } from '../utils/route.decorator'; import ResponseUtil from "../utils/ResponseUtil"; import { Auth } from "../filter/auth"; import { TokenUtil } from "./token_util"; export class DecoratorController { // http://127.0.0.1:3000/api/v1/user2/2 @Route('get', '/user2/:id') async getUserById(req: Request, res: Response) { const { id } = req.params; // 从动态路由中提取参数 const data = { id }; // 假设这里是异步数据库查询操作 await new Promise((resolve) => setTimeout(resolve, 100)); // 模拟延迟 ResponseUtil.success(res, data, '查询成功', 20000); } // 登录验证 // http://127.0.0.1:3000/api/v1/user3/2 @Route('get', '/user3/:id') @Auth(TokenUtil.validateToken) // 应用 Auth 装饰器 async getUserById2(req: Request, res: Response) { const { id } = req.params; // 从动态路由中提取参数 const data = { id }; console.log('999'); // 假设这里是异步数据库查询操作 await new Promise((resolve) => setTimeout(resolve, 100)); // 模拟延迟 ResponseUtil.success(res, data, '查询成功', 20000); } }

留言

专栏
文章
加入群聊