[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"knowledge-\u002Fapi\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fmiddleware":3,"knowledge-related-\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fmiddleware":1548,"knowledge-series-\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fmiddleware":1574},{"source":4,"connector":5,"page":6},"sqlite","better-sqlite3",{"path":7,"title":8,"description":9,"category":10,"tags":11,"date":14,"pinned":15,"draft":15,"body":16,"seo":1544,"stem":1545,"id":1546,"extension":1547},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fmiddleware","中间件 (Middleware)","中间件在路由之前执行，最接近 Express 层。见官方请求生命周期。","技能小册",[12,13],"nestjs","middleware","2021-11-26",false,{"type":17,"value":18,"toc":1534},"minimark",[19,23,26,34,39,116,122,132,136,141,152,468,472,475,552,556,567,782,786,805,921,925,930,979,983,994,1177,1201,1205,1295,1300,1348,1352,1432,1435,1470,1473,1477,1480,1530],[20,21,8],"h1",{"id":22},"中间件-middleware",[24,25,9],"p",{},[24,27,28,29,33],{},"中间件是在路由处理器",[30,31,32],"strong",{},"之前","执行的函数，可以访问请求和响应对象，并能修改它们或结束请求-响应周期。NestJS 的中间件与 Express\u002FFastify 的中间件概念一致，但额外支持依赖注入。",[35,36,38],"h3",{"id":37},"一中间件的特点","一、中间件的特点",[40,41,42,55],"table",{},[43,44,45],"thead",{},[46,47,48,52],"tr",{},[49,50,51],"th",{},"特性",[49,53,54],{},"说明",[56,57,58,74,88,102],"tbody",{},[46,59,60,66],{},[61,62,63],"td",{},[30,64,65],{},"可注入依赖",[61,67,68,69,73],{},"与 Nest 的 IoC 容器集成，可以注入服务（如 ",[70,71,72],"code",{},"LoggerService","）",[46,75,76,81],{},[61,77,78],{},[30,79,80],{},"执行顺序",[61,82,83,84,87],{},"位于",[30,85,86],{},"守卫和管道之前","，即先经过中间件，再进入守卫，最后到管道和控制器",[46,89,90,95],{},[61,91,92],{},[30,93,94],{},"与普通中间件一致",[61,96,97,98,101],{},"可以调用 ",[70,99,100],{},"next()"," 传递给下一个中间件，或者直接发送响应终止流程",[46,103,104,109],{},[61,105,106],{},[30,107,108],{},"局限性",[61,110,111,112,115],{},"无法访问 ",[70,113,114],{},"ExecutionContext","，不能像守卫那样获取执行的控制类\u002F方法元数据",[24,117,118,121],{},[30,119,120],{},"执行顺序示意","：",[123,124,129],"pre",{"className":125,"code":127,"language":128},[126],"language-text","请求 → 中间件 → 守卫 → 管道（验证\u002F转换）→ 控制器 → 拦截器（前置）→ 路由处理器 → 拦截器（后置）→ 响应\n","text",[70,130,127],{"__ignoreMap":131},"",[35,133,135],{"id":134},"二定义中间件","二、定义中间件",[137,138,140],"h4",{"id":139},"_1-类式中间件支持依赖注入","1. 类式中间件（支持依赖注入）",[24,142,143,144,147,148,151],{},"实现 ",[70,145,146],{},"NestMiddleware"," 接口的 ",[70,149,150],{},"use"," 方法。",[123,153,157],{"className":154,"code":155,"language":156,"meta":131,"style":131},"language-ts shiki shiki-themes material-theme-lighter github-light github-dark","import { Injectable, NestMiddleware } from \"@nestjs\u002Fcommon\";\nimport { Request, Response, NextFunction } from \"express\";\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  \u002F\u002F 可以注入其他服务\n  constructor(private readonly logger: LoggerService) {}\n\n  use(req: Request, res: Response, next: NextFunction) {\n    console.log(`[${req.method}] ${req.url}`);\n    this.logger.log(`Request received`);\n    next(); \u002F\u002F 必须调用以传递控制权\n  }\n}\n","ts",[70,158,159,202,235,242,255,277,284,316,321,359,412,441,456,462],{"__ignoreMap":131},[160,161,164,168,172,176,179,182,185,188,192,196,199],"span",{"class":162,"line":163},"line",1,[160,165,167],{"class":166},"sVHd0","import",[160,169,171],{"class":170},"sP7_E"," {",[160,173,175],{"class":174},"su5hD"," Injectable",[160,177,178],{"class":170},",",[160,180,181],{"class":174}," NestMiddleware",[160,183,184],{"class":170}," }",[160,186,187],{"class":166}," from",[160,189,191],{"class":190},"sjJ54"," \"",[160,193,195],{"class":194},"s_sjI","@nestjs\u002Fcommon",[160,197,198],{"class":190},"\"",[160,200,201],{"class":170},";\n",[160,203,205,207,209,212,214,217,219,222,224,226,228,231,233],{"class":162,"line":204},2,[160,206,167],{"class":166},[160,208,171],{"class":170},[160,210,211],{"class":174}," Request",[160,213,178],{"class":170},[160,215,216],{"class":174}," Response",[160,218,178],{"class":170},[160,220,221],{"class":174}," NextFunction",[160,223,184],{"class":170},[160,225,187],{"class":166},[160,227,191],{"class":190},[160,229,230],{"class":194},"express",[160,232,198],{"class":190},[160,234,201],{"class":170},[160,236,238],{"class":162,"line":237},3,[160,239,241],{"emptyLinePlaceholder":240},true,"\n",[160,243,245,248,252],{"class":162,"line":244},4,[160,246,247],{"class":170},"@",[160,249,251],{"class":250},"sGLFI","Injectable",[160,253,254],{"class":174},"()\n",[160,256,258,261,265,269,272,274],{"class":162,"line":257},5,[160,259,260],{"class":166},"export",[160,262,264],{"class":263},"sbsja"," class",[160,266,268],{"class":267},"sbgvK"," LoggerMiddleware",[160,270,271],{"class":263}," implements",[160,273,181],{"class":267},[160,275,276],{"class":170}," {\n",[160,278,280],{"class":162,"line":279},6,[160,281,283],{"class":282},"sutJx","  \u002F\u002F 可以注入其他服务\n",[160,285,287,290,293,296,299,303,307,310,313],{"class":162,"line":286},7,[160,288,289],{"class":263},"  constructor",[160,291,292],{"class":170},"(",[160,294,295],{"class":263},"private",[160,297,298],{"class":263}," readonly",[160,300,302],{"class":301},"s99_P"," logger",[160,304,306],{"class":305},"smGrS",":",[160,308,309],{"class":267}," LoggerService",[160,311,312],{"class":170},")",[160,314,315],{"class":170}," {}\n",[160,317,319],{"class":162,"line":318},8,[160,320,241],{"emptyLinePlaceholder":240},[160,322,324,328,330,333,335,337,339,342,344,346,348,351,353,355,357],{"class":162,"line":323},9,[160,325,327],{"class":326},"sVXei","  use",[160,329,292],{"class":170},[160,331,332],{"class":301},"req",[160,334,306],{"class":305},[160,336,211],{"class":267},[160,338,178],{"class":170},[160,340,341],{"class":301}," res",[160,343,306],{"class":305},[160,345,216],{"class":267},[160,347,178],{"class":170},[160,349,350],{"class":301}," next",[160,352,306],{"class":305},[160,354,221],{"class":267},[160,356,312],{"class":170},[160,358,276],{"class":170},[160,360,362,365,368,371,374,377,380,383,385,387,390,393,396,398,400,402,405,408,410],{"class":162,"line":361},10,[160,363,364],{"class":174},"    console",[160,366,367],{"class":170},".",[160,369,370],{"class":250},"log",[160,372,292],{"class":373},"skxfh",[160,375,376],{"class":190},"`",[160,378,379],{"class":194},"[",[160,381,382],{"class":190},"${",[160,384,332],{"class":174},[160,386,367],{"class":190},[160,388,389],{"class":174},"method",[160,391,392],{"class":190},"}",[160,394,395],{"class":194},"] ",[160,397,382],{"class":190},[160,399,332],{"class":174},[160,401,367],{"class":190},[160,403,404],{"class":174},"url",[160,406,407],{"class":190},"}`",[160,409,312],{"class":373},[160,411,201],{"class":170},[160,413,415,419,421,424,426,428,430,432,435,437,439],{"class":162,"line":414},11,[160,416,418],{"class":417},"s39Yj","    this",[160,420,367],{"class":170},[160,422,423],{"class":174},"logger",[160,425,367],{"class":170},[160,427,370],{"class":250},[160,429,292],{"class":373},[160,431,376],{"class":190},[160,433,434],{"class":194},"Request received",[160,436,376],{"class":190},[160,438,312],{"class":373},[160,440,201],{"class":170},[160,442,444,447,450,453],{"class":162,"line":443},12,[160,445,446],{"class":250},"    next",[160,448,449],{"class":373},"()",[160,451,452],{"class":170},";",[160,454,455],{"class":282}," \u002F\u002F 必须调用以传递控制权\n",[160,457,459],{"class":162,"line":458},13,[160,460,461],{"class":170},"  }\n",[160,463,465],{"class":162,"line":464},14,[160,466,467],{"class":170},"}\n",[137,469,471],{"id":470},"_2-函数式中间件简单场景","2. 函数式中间件（简单场景）",[24,473,474],{},"对于没有依赖的简单中间件，可以使用函数形式。",[123,476,478],{"className":154,"code":477,"language":156,"meta":131,"style":131},"export function logger(req: Request, res: Response, next: NextFunction) {\n  console.log(`Request...`);\n  next();\n}\n",[70,479,480,517,539,548],{"__ignoreMap":131},[160,481,482,484,487,489,491,493,495,497,499,501,503,505,507,509,511,513,515],{"class":162,"line":163},[160,483,260],{"class":166},[160,485,486],{"class":263}," function",[160,488,302],{"class":250},[160,490,292],{"class":170},[160,492,332],{"class":301},[160,494,306],{"class":305},[160,496,211],{"class":267},[160,498,178],{"class":170},[160,500,341],{"class":301},[160,502,306],{"class":305},[160,504,216],{"class":267},[160,506,178],{"class":170},[160,508,350],{"class":301},[160,510,306],{"class":305},[160,512,221],{"class":267},[160,514,312],{"class":170},[160,516,276],{"class":170},[160,518,519,522,524,526,528,530,533,535,537],{"class":162,"line":204},[160,520,521],{"class":174},"  console",[160,523,367],{"class":170},[160,525,370],{"class":250},[160,527,292],{"class":373},[160,529,376],{"class":190},[160,531,532],{"class":194},"Request...",[160,534,376],{"class":190},[160,536,312],{"class":373},[160,538,201],{"class":170},[160,540,541,544,546],{"class":162,"line":237},[160,542,543],{"class":250},"  next",[160,545,449],{"class":373},[160,547,201],{"class":170},[160,549,550],{"class":162,"line":244},[160,551,467],{"class":170},[35,553,555],{"id":554},"三配置中间件","三、配置中间件",[24,557,558,559,562,563,566],{},"中间件需要在某个模块中通过 ",[70,560,561],{},"MiddlewareConsumer"," 进行配置，通常在模块的 ",[70,564,565],{},"configure"," 方法中。",[123,568,570],{"className":154,"code":569,"language":156,"meta":131,"style":131},"import { Module, NestModule, MiddlewareConsumer } from \"@nestjs\u002Fcommon\";\nimport { LoggerMiddleware } from \".\u002Flogger.middleware\";\nimport { UsersController } from \".\u002Fusers.controller\";\n\n@Module({\n  controllers: [UsersController],\n})\nexport class UsersModule implements NestModule {\n  configure(consumer: MiddlewareConsumer) {\n    consumer\n      .apply(LoggerMiddleware) \u002F\u002F 应用中间件（可以多个）\n      .forRoutes(\"users\"); \u002F\u002F 指定路由路径（字符串或路由对象）\n    \u002F\u002F 或者 forRoutes(UsersController) 应用到控制器所有路由\n    \u002F\u002F 或者 forRoutes({ path: 'users', method: RequestMethod.GET })\n  }\n}\n",[70,571,572,603,624,646,650,662,675,682,697,715,720,739,762,767,772,777],{"__ignoreMap":131},[160,573,574,576,578,581,583,586,588,591,593,595,597,599,601],{"class":162,"line":163},[160,575,167],{"class":166},[160,577,171],{"class":170},[160,579,580],{"class":174}," Module",[160,582,178],{"class":170},[160,584,585],{"class":174}," NestModule",[160,587,178],{"class":170},[160,589,590],{"class":174}," MiddlewareConsumer",[160,592,184],{"class":170},[160,594,187],{"class":166},[160,596,191],{"class":190},[160,598,195],{"class":194},[160,600,198],{"class":190},[160,602,201],{"class":170},[160,604,605,607,609,611,613,615,617,620,622],{"class":162,"line":204},[160,606,167],{"class":166},[160,608,171],{"class":170},[160,610,268],{"class":174},[160,612,184],{"class":170},[160,614,187],{"class":166},[160,616,191],{"class":190},[160,618,619],{"class":194},".\u002Flogger.middleware",[160,621,198],{"class":190},[160,623,201],{"class":170},[160,625,626,628,630,633,635,637,639,642,644],{"class":162,"line":237},[160,627,167],{"class":166},[160,629,171],{"class":170},[160,631,632],{"class":174}," UsersController",[160,634,184],{"class":170},[160,636,187],{"class":166},[160,638,191],{"class":190},[160,640,641],{"class":194},".\u002Fusers.controller",[160,643,198],{"class":190},[160,645,201],{"class":170},[160,647,648],{"class":162,"line":244},[160,649,241],{"emptyLinePlaceholder":240},[160,651,652,654,657,659],{"class":162,"line":257},[160,653,247],{"class":170},[160,655,656],{"class":250},"Module",[160,658,292],{"class":174},[160,660,661],{"class":170},"{\n",[160,663,664,667,669,672],{"class":162,"line":279},[160,665,666],{"class":373},"  controllers",[160,668,306],{"class":170},[160,670,671],{"class":174}," [UsersController]",[160,673,674],{"class":170},",\n",[160,676,677,679],{"class":162,"line":286},[160,678,392],{"class":170},[160,680,681],{"class":174},")\n",[160,683,684,686,688,691,693,695],{"class":162,"line":318},[160,685,260],{"class":166},[160,687,264],{"class":263},[160,689,690],{"class":267}," UsersModule",[160,692,271],{"class":263},[160,694,585],{"class":267},[160,696,276],{"class":170},[160,698,699,702,704,707,709,711,713],{"class":162,"line":323},[160,700,701],{"class":326},"  configure",[160,703,292],{"class":170},[160,705,706],{"class":301},"consumer",[160,708,306],{"class":305},[160,710,590],{"class":267},[160,712,312],{"class":170},[160,714,276],{"class":170},[160,716,717],{"class":162,"line":361},[160,718,719],{"class":174},"    consumer\n",[160,721,722,725,728,730,733,736],{"class":162,"line":414},[160,723,724],{"class":170},"      .",[160,726,727],{"class":250},"apply",[160,729,292],{"class":373},[160,731,732],{"class":174},"LoggerMiddleware",[160,734,735],{"class":373},") ",[160,737,738],{"class":282},"\u002F\u002F 应用中间件（可以多个）\n",[160,740,741,743,746,748,750,753,755,757,759],{"class":162,"line":443},[160,742,724],{"class":170},[160,744,745],{"class":250},"forRoutes",[160,747,292],{"class":373},[160,749,198],{"class":190},[160,751,752],{"class":194},"users",[160,754,198],{"class":190},[160,756,312],{"class":373},[160,758,452],{"class":170},[160,760,761],{"class":282}," \u002F\u002F 指定路由路径（字符串或路由对象）\n",[160,763,764],{"class":162,"line":458},[160,765,766],{"class":282},"    \u002F\u002F 或者 forRoutes(UsersController) 应用到控制器所有路由\n",[160,768,769],{"class":162,"line":464},[160,770,771],{"class":282},"    \u002F\u002F 或者 forRoutes({ path: 'users', method: RequestMethod.GET })\n",[160,773,775],{"class":162,"line":774},15,[160,776,461],{"class":170},[160,778,780],{"class":162,"line":779},16,[160,781,467],{"class":170},[137,783,785],{"id":784},"_1-路径匹配与排除","1. 路径匹配与排除",[787,788,789,797],"ul",{},[790,791,792,796],"li",{},[30,793,794],{},[70,795,745],{},"：可接受控制器类、路由字符串或路由对象。",[790,798,799,804],{},[30,800,801],{},[70,802,803],{},"exclude","：排除某些路径不应用中间件。",[123,806,808],{"className":154,"code":807,"language":156,"meta":131,"style":131},"consumer\n  .apply(LoggerMiddleware)\n  .exclude(\n    { path: \"users\", method: RequestMethod.POST }, \u002F\u002F 排除 POST \u002Fusers\n    { path: \"users\u002F(.*)\", method: RequestMethod.ALL }, \u002F\u002F 排除所有 \u002Fusers\u002F* 路由\n  )\n  .forRoutes(UsersController);\n",[70,809,810,815,825,834,872,905,910],{"__ignoreMap":131},[160,811,812],{"class":162,"line":163},[160,813,814],{"class":174},"consumer\n",[160,816,817,820,822],{"class":162,"line":204},[160,818,819],{"class":170},"  .",[160,821,727],{"class":250},[160,823,824],{"class":174},"(LoggerMiddleware)\n",[160,826,827,829,831],{"class":162,"line":237},[160,828,819],{"class":170},[160,830,803],{"class":250},[160,832,833],{"class":174},"(\n",[160,835,836,839,842,844,846,848,850,852,855,857,860,862,866,869],{"class":162,"line":244},[160,837,838],{"class":170},"    {",[160,840,841],{"class":373}," path",[160,843,306],{"class":170},[160,845,191],{"class":190},[160,847,752],{"class":194},[160,849,198],{"class":190},[160,851,178],{"class":170},[160,853,854],{"class":373}," method",[160,856,306],{"class":170},[160,858,859],{"class":174}," RequestMethod",[160,861,367],{"class":170},[160,863,865],{"class":864},"s_hVV","POST",[160,867,868],{"class":170}," },",[160,870,871],{"class":282}," \u002F\u002F 排除 POST \u002Fusers\n",[160,873,874,876,878,880,882,885,887,889,891,893,895,897,900,902],{"class":162,"line":257},[160,875,838],{"class":170},[160,877,841],{"class":373},[160,879,306],{"class":170},[160,881,191],{"class":190},[160,883,884],{"class":194},"users\u002F(.*)",[160,886,198],{"class":190},[160,888,178],{"class":170},[160,890,854],{"class":373},[160,892,306],{"class":170},[160,894,859],{"class":174},[160,896,367],{"class":170},[160,898,899],{"class":864},"ALL",[160,901,868],{"class":170},[160,903,904],{"class":282}," \u002F\u002F 排除所有 \u002Fusers\u002F* 路由\n",[160,906,907],{"class":162,"line":279},[160,908,909],{"class":174},"  )\n",[160,911,912,914,916,919],{"class":162,"line":286},[160,913,819],{"class":170},[160,915,745],{"class":250},[160,917,918],{"class":174},"(UsersController)",[160,920,201],{"class":170},[137,922,924],{"id":923},"_2-应用多个中间件","2. 应用多个中间件",[24,926,927,929],{},[70,928,727],{}," 可以接受逗号分隔的多个中间件。",[123,931,933],{"className":154,"code":932,"language":156,"meta":131,"style":131},"consumer.apply(cors(), helmet(), LoggerMiddleware).forRoutes(\"*\");\n",[70,934,935],{"__ignoreMap":131},[160,936,937,939,941,943,945,948,950,952,955,957,959,962,964,966,968,970,973,975,977],{"class":162,"line":163},[160,938,706],{"class":174},[160,940,367],{"class":170},[160,942,727],{"class":250},[160,944,292],{"class":174},[160,946,947],{"class":250},"cors",[160,949,449],{"class":174},[160,951,178],{"class":170},[160,953,954],{"class":250}," helmet",[160,956,449],{"class":174},[160,958,178],{"class":170},[160,960,961],{"class":174}," LoggerMiddleware)",[160,963,367],{"class":170},[160,965,745],{"class":250},[160,967,292],{"class":174},[160,969,198],{"class":190},[160,971,972],{"class":194},"*",[160,974,198],{"class":190},[160,976,312],{"class":174},[160,978,201],{"class":170},[35,980,982],{"id":981},"四全局中间件","四、全局中间件",[24,984,985,986,989,990,993],{},"如果希望中间件应用于所有路由（如 CORS、Helmet），可以在 ",[70,987,988],{},"main.ts"," 中直接使用 ",[70,991,992],{},"app.use()","。",[123,995,997],{"className":154,"code":996,"language":156,"meta":131,"style":131},"\u002F\u002F main.ts\nimport { NestFactory } from \"@nestjs\u002Fcore\";\nimport { AppModule } from \".\u002Fapp.module\";\nimport { logger } from \".\u002Fcommon\u002Fmiddleware\u002Flogger.middleware\";\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.use(logger); \u002F\u002F 函数式中间件\n  \u002F\u002F 或者 app.use(new LoggerMiddleware().use) 但无法注入依赖\n  await app.listen(3000);\n}\nbootstrap();\n",[70,998,999,1004,1026,1048,1069,1073,1087,1117,1137,1142,1164,1168],{"__ignoreMap":131},[160,1000,1001],{"class":162,"line":163},[160,1002,1003],{"class":282},"\u002F\u002F main.ts\n",[160,1005,1006,1008,1010,1013,1015,1017,1019,1022,1024],{"class":162,"line":204},[160,1007,167],{"class":166},[160,1009,171],{"class":170},[160,1011,1012],{"class":174}," NestFactory",[160,1014,184],{"class":170},[160,1016,187],{"class":166},[160,1018,191],{"class":190},[160,1020,1021],{"class":194},"@nestjs\u002Fcore",[160,1023,198],{"class":190},[160,1025,201],{"class":170},[160,1027,1028,1030,1032,1035,1037,1039,1041,1044,1046],{"class":162,"line":237},[160,1029,167],{"class":166},[160,1031,171],{"class":170},[160,1033,1034],{"class":174}," AppModule",[160,1036,184],{"class":170},[160,1038,187],{"class":166},[160,1040,191],{"class":190},[160,1042,1043],{"class":194},".\u002Fapp.module",[160,1045,198],{"class":190},[160,1047,201],{"class":170},[160,1049,1050,1052,1054,1056,1058,1060,1062,1065,1067],{"class":162,"line":244},[160,1051,167],{"class":166},[160,1053,171],{"class":170},[160,1055,302],{"class":174},[160,1057,184],{"class":170},[160,1059,187],{"class":166},[160,1061,191],{"class":190},[160,1063,1064],{"class":194},".\u002Fcommon\u002Fmiddleware\u002Flogger.middleware",[160,1066,198],{"class":190},[160,1068,201],{"class":170},[160,1070,1071],{"class":162,"line":257},[160,1072,241],{"emptyLinePlaceholder":240},[160,1074,1075,1078,1080,1083,1085],{"class":162,"line":279},[160,1076,1077],{"class":263},"async",[160,1079,486],{"class":263},[160,1081,1082],{"class":250}," bootstrap",[160,1084,449],{"class":170},[160,1086,276],{"class":170},[160,1088,1089,1092,1095,1098,1101,1103,1105,1108,1110,1113,1115],{"class":162,"line":286},[160,1090,1091],{"class":263},"  const",[160,1093,1094],{"class":864}," app",[160,1096,1097],{"class":305}," =",[160,1099,1100],{"class":166}," await",[160,1102,1012],{"class":174},[160,1104,367],{"class":170},[160,1106,1107],{"class":250},"create",[160,1109,292],{"class":373},[160,1111,1112],{"class":174},"AppModule",[160,1114,312],{"class":373},[160,1116,201],{"class":170},[160,1118,1119,1122,1124,1126,1128,1130,1132,1134],{"class":162,"line":318},[160,1120,1121],{"class":174},"  app",[160,1123,367],{"class":170},[160,1125,150],{"class":250},[160,1127,292],{"class":373},[160,1129,423],{"class":174},[160,1131,312],{"class":373},[160,1133,452],{"class":170},[160,1135,1136],{"class":282}," \u002F\u002F 函数式中间件\n",[160,1138,1139],{"class":162,"line":323},[160,1140,1141],{"class":282},"  \u002F\u002F 或者 app.use(new LoggerMiddleware().use) 但无法注入依赖\n",[160,1143,1144,1147,1149,1151,1154,1156,1160,1162],{"class":162,"line":361},[160,1145,1146],{"class":166},"  await",[160,1148,1094],{"class":174},[160,1150,367],{"class":170},[160,1152,1153],{"class":250},"listen",[160,1155,292],{"class":373},[160,1157,1159],{"class":1158},"srdBf","3000",[160,1161,312],{"class":373},[160,1163,201],{"class":170},[160,1165,1166],{"class":162,"line":414},[160,1167,467],{"class":170},[160,1169,1170,1173,1175],{"class":162,"line":443},[160,1171,1172],{"class":250},"bootstrap",[160,1174,449],{"class":174},[160,1176,201],{"class":170},[24,1178,1179,1182,1183,1186,1187,1190,1191,1193,1194,1196,1197,1200],{},[30,1180,1181],{},"注意","：全局中间件无法通过类形式获得依赖注入（除非使用 ",[70,1184,1185],{},"APP_MIDDLEWARE"," 令牌？实际上常规 ",[70,1188,1189],{},"app.use"," 不支持 DI），如果需要 DI 的全局中间件，可以创建一个模块实现 ",[70,1192,561],{}," 并配置 ",[70,1195,972],{}," 路径，但这样每个模块都需要导入该模块。更简单的方式是使用",[30,1198,1199],{},"全局守卫\u002F拦截器","代替。",[35,1202,1204],{"id":1203},"五常见用途","五、常见用途",[40,1206,1207,1216],{},[43,1208,1209],{},[46,1210,1211,1214],{},[49,1212,1213],{},"用途",[49,1215,54],{},[56,1217,1218,1228,1238,1255,1268,1282],{},[46,1219,1220,1225],{},[61,1221,1222],{},[30,1223,1224],{},"日志记录",[61,1226,1227],{},"记录每个请求的方法、URL、响应时间等",[46,1229,1230,1235],{},[61,1231,1232],{},[30,1233,1234],{},"请求预处理",[61,1236,1237],{},"解析自定义请求头、注入请求上下文",[46,1239,1240,1245],{},[61,1241,1242],{},[30,1243,1244],{},"CORS",[61,1246,1247,1248,1251,1252,73],{},"使用 NestJS 内置 ",[70,1249,1250],{},"cors()"," 中间件（通过 ",[70,1253,1254],{},"app.enableCors()",[46,1256,1257,1262],{},[61,1258,1259],{},[30,1260,1261],{},"Helmet",[61,1263,1264,1265],{},"设置安全相关的 HTTP 头：",[70,1266,1267],{},"app.use(helmet())",[46,1269,1270,1275],{},[61,1271,1272],{},[30,1273,1274],{},"压缩",[61,1276,1277,1278,1281],{},"启用响应压缩（如 ",[70,1279,1280],{},"compression"," 中间件）",[46,1283,1284,1289],{},[61,1285,1286],{},[30,1287,1288],{},"限流",[61,1290,1291,1292,73],{},"实现简单的请求频率限制（如 ",[70,1293,1294],{},"express-rate-limit",[24,1296,1297,121],{},[30,1298,1299],{},"CORS 启用示例",[123,1301,1303],{"className":154,"code":1302,"language":156,"meta":131,"style":131},"\u002F\u002F main.ts\nconst app = await NestFactory.create(AppModule);\napp.enableCors(); \u002F\u002F 也可以传入配置对象\n",[70,1304,1305,1309,1331],{"__ignoreMap":131},[160,1306,1307],{"class":162,"line":163},[160,1308,1003],{"class":282},[160,1310,1311,1314,1316,1318,1320,1322,1324,1326,1329],{"class":162,"line":204},[160,1312,1313],{"class":263},"const",[160,1315,1094],{"class":864},[160,1317,1097],{"class":305},[160,1319,1100],{"class":166},[160,1321,1012],{"class":174},[160,1323,367],{"class":170},[160,1325,1107],{"class":250},[160,1327,1328],{"class":174},"(AppModule)",[160,1330,201],{"class":170},[160,1332,1333,1336,1338,1341,1343,1345],{"class":162,"line":237},[160,1334,1335],{"class":174},"app",[160,1337,367],{"class":170},[160,1339,1340],{"class":250},"enableCors",[160,1342,449],{"class":174},[160,1344,452],{"class":170},[160,1346,1347],{"class":282}," \u002F\u002F 也可以传入配置对象\n",[35,1349,1351],{"id":1350},"六中间件与守卫管道的区别","六、中间件与守卫、管道的区别",[40,1353,1354,1370],{},[43,1355,1356],{},[46,1357,1358,1361,1364,1367],{},[49,1359,1360],{},"组件",[49,1362,1363],{},"执行时机",[49,1365,1366],{},"可访问内容",[49,1368,1369],{},"主要用途",[56,1371,1372,1394,1412],{},[46,1373,1374,1379,1382,1391],{},[61,1375,1376],{},[30,1377,1378],{},"中间件",[61,1380,1381],{},"最早（路由匹配后，守卫之前）",[61,1383,1384,1387,1388],{},[70,1385,1386],{},"Request",", ",[70,1389,1390],{},"Response",[61,1392,1393],{},"日志、预处理、跨域等",[46,1395,1396,1401,1404,1409],{},[61,1397,1398],{},[30,1399,1400],{},"守卫",[61,1402,1403],{},"中间件之后，管道之前",[61,1405,1406,1408],{},[70,1407,114],{},"，可获取元数据",[61,1410,1411],{},"鉴权、授权",[46,1413,1414,1419,1422,1429],{},[61,1415,1416],{},[30,1417,1418],{},"管道",[61,1420,1421],{},"守卫之后，控制器之前",[61,1423,1424,1425,1428],{},"参数（如 ",[70,1426,1427],{},"@Body"," 等）",[61,1430,1431],{},"验证、转换",[35,1433,1434],{"id":1434},"总结",[787,1436,1437,1451,1461,1467],{},[790,1438,1439,1442,1443,1446,1447,1450],{},[30,1440,1441],{},"类式中间件","通过 ",[70,1444,1445],{},"@Injectable()"," 支持依赖注入；",[30,1448,1449],{},"函数式中间件","更简单，适用于无依赖场景。",[790,1452,1453,1454,1457,1458,1460],{},"在模块中实现 ",[70,1455,1456],{},"NestModule"," 接口，通过 ",[70,1459,561],{}," 配置中间件的应用路由、排除路径。",[790,1462,1463,1464,1466],{},"全局中间件使用 ",[70,1465,992],{}," 注册，但无法注入依赖。",[790,1468,1469],{},"常用场景：日志、安全头（Helmet）、CORS、请求预处理等。",[24,1471,1472],{},"掌握中间件，可以在请求生命周期的早期阶段进行统一处理，而不侵入业务逻辑。",[1474,1475,1476],"h2",{"id":1476},"参考文献",[24,1478,1479],{},"以下链接在编写时均可正常访问：",[40,1481,1482,1491],{},[43,1483,1484],{},[46,1485,1486,1489],{},[49,1487,1488],{},"资料",[49,1490,54],{},[56,1492,1493,1507,1519],{},[46,1494,1495,1504],{},[61,1496,1497],{},[1498,1499,1503],"a",{"href":1500,"rel":1501},"https:\u002F\u002Fdocs.nestjs.com\u002F",[1502],"nofollow","NestJS 文档",[61,1505,1506],{},"官方",[46,1508,1509,1516],{},[61,1510,1511],{},[1498,1512,1515],{"href":1513,"rel":1514},"https:\u002F\u002Fdocs.nestjs.com\u002Fmiddleware",[1502],"Middleware",[61,1517,1518],{},"本章主题",[46,1520,1521,1528],{},[61,1522,1523],{},[1498,1524,1527],{"href":1525,"rel":1526},"https:\u002F\u002Fdocs.nestjs.com\u002Ffaq\u002Frequest-lifecycle",[1502],"Request lifecycle",[61,1529,80],{},[1531,1532,1533],"style",{},"html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .s99_P, html code.shiki .s99_P{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVXei, html code.shiki .sVXei{--shiki-light:#E53935;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":131,"searchDepth":204,"depth":204,"links":1535},[1536,1537,1538,1539,1540,1541,1542,1543],{"id":37,"depth":237,"text":38},{"id":134,"depth":237,"text":135},{"id":554,"depth":237,"text":555},{"id":981,"depth":237,"text":982},{"id":1203,"depth":237,"text":1204},{"id":1350,"depth":237,"text":1351},{"id":1434,"depth":237,"text":1434},{"id":1476,"depth":204,"text":1476},{"title":8,"description":9},"knowledge\u002Fbooklet\u002Fend\u002FNestJS\u002Fnew\u002Fmiddleware","knowledge\u002Fknowledge\u002Fbooklet\u002Fend\u002FNestJS\u002Fnew\u002Fmiddleware.md","md",{"items":1549},[1550,1554,1558,1562,1566,1570],{"path":1551,"title":1552,"description":1553,"category":10,"score":279},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fauth","认证与授权","认证（Authentication）：确认「你是谁」（如 JWT、Session）。 - 授权（Authorization）：确认「你能做什么」（如 RBAC、策略检查）。",{"path":1555,"title":1556,"description":1557,"category":10,"score":279},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fcache","缓存","@nestjs\u002Fcache-manager 统一缓存 API，存储实现可插拔。",{"path":1559,"title":1560,"description":1561,"category":10,"score":279},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fservice","提供者与服务","Service 是最常见的 Provider，封装业务逻辑。见 module。",{"path":1563,"title":1564,"description":1565,"category":10,"score":279},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fguards","守卫 (Guards) 与授权","守卫决定是否放行请求，常用于认证与授权。见 auth。",{"path":1567,"title":1568,"description":1569,"category":10,"score":279},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fconfig","配置管理（Config 模块）","@nestjs\u002Fconfig 加载 .env 并提供 ConfigService。见 工程化 env。",{"path":1571,"title":1572,"description":1573,"category":10,"score":279},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fdatabase","数据库集成（以 TypeORM 为例）","Nest 通过 @nestjs\u002Ftypeorm 等包集成 ORM；生产环境用 migration，慎用 synchronize。亦可选用 Prisma、MikroORM 等（见 官方 Database）。",{"series":1575,"title":1576,"items":1577,"index":458,"prev":1637,"next":1638},"booklet\u002Fend\u002Fnestjs\u002Fnew","new",[1578,1580,1584,1586,1588,1592,1596,1600,1602,1606,1610,1612,1616,1619,1620,1624,1627,1631,1633],{"path":1551,"title":1552,"date":1579,"pinned":15},"2025-12-23",{"path":1581,"title":1582,"date":1583,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fbase","NestJS 基础","2021-03-09",{"path":1555,"title":1556,"date":1585,"pinned":15},"2025-07-04",{"path":1567,"title":1568,"date":1587,"pinned":15},"2023-08-26",{"path":1589,"title":1590,"date":1591,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fcontroller","控制器与路由","2020-07-18",{"path":1593,"title":1594,"date":1595,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fcron","定时任务","2023-04-12",{"path":1597,"title":1598,"date":1599,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fcustom-decorators","自定义装饰器","2021-09-19",{"path":1571,"title":1572,"date":1601,"pinned":15},"2023-05-26",{"path":1603,"title":1604,"date":1605,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fdeploy","部署与运维","2023-01-24",{"path":1607,"title":1608,"date":1609,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Ferror","异常处理","2020-01-28",{"path":1563,"title":1564,"date":1611,"pinned":15},"2023-09-09",{"path":1613,"title":1614,"date":1615,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fintercept","拦截器 (Interceptors)","2021-04-26",{"path":1617,"title":1224,"date":1618,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Flogger","2022-10-10",{"path":7,"title":8,"date":14,"pinned":15},{"path":1621,"title":1622,"date":1623,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fmodule","模块系统与依赖注入","2022-06-15",{"path":1625,"title":1626,"date":1591,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fpipes","管道 (Pipes) 与数据验证",{"path":1628,"title":1629,"date":1630,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fqueue","队列（Bull）","2021-07-01",{"path":1559,"title":1560,"date":1632,"pinned":15},"2024-12-02",{"path":1634,"title":1635,"date":1636,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fwebsocket","WebSocket（网关）","2022-12-14",{"path":1617,"title":1224,"date":1618,"pinned":15},{"path":1621,"title":1622,"date":1623,"pinned":15}]