[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"knowledge-\u002Fapi\u002Fknowledge\u002Fbooklet\u002Fend\u002Fexpress":3,"knowledge-related-\u002Fknowledge\u002Fbooklet\u002Fend\u002Fexpress":4641,"knowledge-series-\u002Fknowledge\u002Fbooklet\u002Fend\u002Fexpress":4664},{"source":4,"connector":5,"page":6},"sqlite","better-sqlite3",{"path":7,"title":8,"description":9,"category":10,"tags":11,"date":13,"pinned":14,"draft":14,"body":15,"seo":4637,"stem":4638,"id":4639,"extension":4640},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fexpress","Express","Express 是运行在 Node.js 之上的极简 Web 框架，提供路由、中间件与 HTTP 工具。见 后端入门概览、EJS。","技能小册",[12],"express","2022-01-24",false,{"type":16,"value":17,"toc":4609},"minimark",[18,21,46,51,90,94,99,177,181,404,408,415,432,439,500,507,511,517,651,654,974,993,997,1004,1128,1131,1456,1460,1463,1467,1867,1871,2058,2066,2072,2489,2636,2640,2652,2656,2987,2991,3047,3050,3547,3551,3554,3730,3747,3751,3760,3764,3767,3839,3843,3851,4121,4125,4132,4408,4412,4550,4553,4556,4605],[19,20,8],"h1",{"id":12},[22,23,24,30,31,35,36,40,41,45],"p",{},[25,26,8],"a",{"href":27,"rel":28},"https:\u002F\u002Fexpressjs.com\u002F",[29],"nofollow"," 是运行在 ",[32,33,34],"strong",{},"Node.js"," 之上的极简 Web 框架，提供路由、中间件与 HTTP 工具。见 ",[25,37,39],{"href":38},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fbasics","后端入门概览","、",[25,42,44],{"href":43},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fejs","EJS","。",[47,48,50],"h2",{"id":49},"一express-基础概念","一、Express 基础概念",[52,53,54,61,84],"ul",{},[55,56,57,60],"li",{},[32,58,59],{},"什么是 Express","：Node.js 中最流行的 Web 开发框架，基于 Node.js 原生 HTTP 模块构建，提供了路由、中间件、模板引擎等核心能力，被用于构建 RESTful API、Web 网站、单页应用（SPA）后端等开发场景。",[55,62,63,66,67],{},[32,64,65],{},"核心特点","：\n",[52,68,69,72,75,78,81],{},[55,70,71],{},"极简而灵活，开发者可以根据需求组合中间件和工具",[55,73,74],{},"基于中间件架构，处理请求的生命周期被拆分为多个可插拔的函数",[55,76,77],{},"强大的路由系统，支持参数、正则表达式、模块化路由",[55,79,80],{},"内置错误处理，便于进行异步和同步错误的统一管理",[55,82,83],{},"与各种模板引擎（如 EJS、Pug）无缝集成",[55,85,86,89],{},[32,87,88],{},"Express vs Node.js 原生 HTTP","：Express 在 Node.js 的 http 模块之上做了封装，提供了更便捷的 API，降低了直接处理请求、路由匹配和响应处理的复杂度。",[47,91,93],{"id":92},"二安装与环境","二、安装与环境",[95,96,98],"h3",{"id":97},"_1-安装-express","1. 安装 Express",[100,101,106],"pre",{"className":102,"code":103,"language":104,"meta":105,"style":105},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark","# 创建项目目录并初始化\nmkdir my-app && cd my-app\nnpm init -y\n\n# 安装 Express\nnpm install express\n","bash","",[107,108,109,118,140,153,160,166],"code",{"__ignoreMap":105},[110,111,114],"span",{"class":112,"line":113},"line",1,[110,115,117],{"class":116},"sutJx","# 创建项目目录并初始化\n",[110,119,121,125,129,133,137],{"class":112,"line":120},2,[110,122,124],{"class":123},"sbgvK","mkdir",[110,126,128],{"class":127},"s_sjI"," my-app",[110,130,132],{"class":131},"sP7_E"," &&",[110,134,136],{"class":135},"sptTA"," cd",[110,138,139],{"class":127}," my-app\n",[110,141,143,146,149],{"class":112,"line":142},3,[110,144,145],{"class":123},"npm",[110,147,148],{"class":127}," init",[110,150,152],{"class":151},"stzsN"," -y\n",[110,154,156],{"class":112,"line":155},4,[110,157,159],{"emptyLinePlaceholder":158},true,"\n",[110,161,163],{"class":112,"line":162},5,[110,164,165],{"class":116},"# 安装 Express\n",[110,167,169,171,174],{"class":112,"line":168},6,[110,170,145],{"class":123},[110,172,173],{"class":127}," install",[110,175,176],{"class":127}," express\n",[95,178,180],{"id":179},"_2-最小可用示例","2. 最小可用示例",[100,182,186],{"className":183,"code":184,"language":185,"meta":105,"style":105},"language-javascript shiki shiki-themes material-theme-lighter github-light github-dark","const express = require(\"express\");\nconst app = express();\nconst port = 3000;\n\napp.get(\"\u002F\", (req, res) => {\n  res.send(\"Hello World!\");\n});\n\napp.listen(port, () => {\n  console.log(`服务器运行在 http:\u002F\u002Flocalhost:${port}`);\n});\n","javascript",[107,187,188,224,240,255,259,302,326,336,341,363,395],{"__ignoreMap":105},[110,189,190,194,198,202,206,210,214,216,218,221],{"class":112,"line":113},[110,191,193],{"class":192},"sbsja","const",[110,195,197],{"class":196},"s_hVV"," express",[110,199,201],{"class":200},"smGrS"," =",[110,203,205],{"class":204},"sGLFI"," require",[110,207,209],{"class":208},"su5hD","(",[110,211,213],{"class":212},"sjJ54","\"",[110,215,12],{"class":127},[110,217,213],{"class":212},[110,219,220],{"class":208},")",[110,222,223],{"class":131},";\n",[110,225,226,228,231,233,235,238],{"class":112,"line":120},[110,227,193],{"class":192},[110,229,230],{"class":196}," app",[110,232,201],{"class":200},[110,234,197],{"class":204},[110,236,237],{"class":208},"()",[110,239,223],{"class":131},[110,241,242,244,247,249,253],{"class":112,"line":142},[110,243,193],{"class":192},[110,245,246],{"class":196}," port",[110,248,201],{"class":200},[110,250,252],{"class":251},"srdBf"," 3000",[110,254,223],{"class":131},[110,256,257],{"class":112,"line":155},[110,258,159],{"emptyLinePlaceholder":158},[110,260,261,264,267,270,272,274,277,279,282,285,289,291,294,296,299],{"class":112,"line":162},[110,262,263],{"class":208},"app",[110,265,266],{"class":131},".",[110,268,269],{"class":204},"get",[110,271,209],{"class":208},[110,273,213],{"class":212},[110,275,276],{"class":127},"\u002F",[110,278,213],{"class":212},[110,280,281],{"class":131},",",[110,283,284],{"class":131}," (",[110,286,288],{"class":287},"s99_P","req",[110,290,281],{"class":131},[110,292,293],{"class":287}," res",[110,295,220],{"class":131},[110,297,298],{"class":192}," =>",[110,300,301],{"class":131}," {\n",[110,303,304,307,309,312,315,317,320,322,324],{"class":112,"line":168},[110,305,306],{"class":208},"  res",[110,308,266],{"class":131},[110,310,311],{"class":204},"send",[110,313,209],{"class":314},"skxfh",[110,316,213],{"class":212},[110,318,319],{"class":127},"Hello World!",[110,321,213],{"class":212},[110,323,220],{"class":314},[110,325,223],{"class":131},[110,327,329,332,334],{"class":112,"line":328},7,[110,330,331],{"class":131},"}",[110,333,220],{"class":208},[110,335,223],{"class":131},[110,337,339],{"class":112,"line":338},8,[110,340,159],{"emptyLinePlaceholder":158},[110,342,344,346,348,351,354,356,359,361],{"class":112,"line":343},9,[110,345,263],{"class":208},[110,347,266],{"class":131},[110,349,350],{"class":204},"listen",[110,352,353],{"class":208},"(port",[110,355,281],{"class":131},[110,357,358],{"class":131}," ()",[110,360,298],{"class":192},[110,362,301],{"class":131},[110,364,366,369,371,374,376,379,382,385,388,391,393],{"class":112,"line":365},10,[110,367,368],{"class":208},"  console",[110,370,266],{"class":131},[110,372,373],{"class":204},"log",[110,375,209],{"class":314},[110,377,378],{"class":212},"`",[110,380,381],{"class":127},"服务器运行在 http:\u002F\u002Flocalhost:",[110,383,384],{"class":212},"${",[110,386,387],{"class":208},"port",[110,389,390],{"class":212},"}`",[110,392,220],{"class":314},[110,394,223],{"class":131},[110,396,398,400,402],{"class":112,"line":397},11,[110,399,331],{"class":131},[110,401,220],{"class":208},[110,403,223],{"class":131},[95,405,407],{"id":406},"_3-开启开发模式自动重启","3. 开启开发模式（自动重启）",[22,409,410,411,414],{},"安装 ",[107,412,413],{},"nodemon","：",[100,416,418],{"className":102,"code":417,"language":104,"meta":105,"style":105},"npm install -D nodemon\n",[107,419,420],{"__ignoreMap":105},[110,421,422,424,426,429],{"class":112,"line":113},[110,423,145],{"class":123},[110,425,173],{"class":127},[110,427,428],{"class":151}," -D",[110,430,431],{"class":127}," nodemon\n",[22,433,434,435,438],{},"在 ",[107,436,437],{},"package.json"," 中添加脚本：",[100,440,444],{"className":441,"code":442,"language":443,"meta":105,"style":105},"language-json shiki shiki-themes material-theme-lighter github-light github-dark","{\n  \"scripts\": {\n    \"dev\": \"nodemon app.js\"\n  }\n}\n","json",[107,445,446,451,468,490,495],{"__ignoreMap":105},[110,447,448],{"class":112,"line":113},[110,449,450],{"class":131},"{\n",[110,452,453,457,461,463,466],{"class":112,"line":120},[110,454,456],{"class":455},"s39Yj","  \"",[110,458,460],{"class":459},"sseR_","scripts",[110,462,213],{"class":455},[110,464,465],{"class":131},":",[110,467,301],{"class":131},[110,469,470,473,477,479,481,484,487],{"class":112,"line":142},[110,471,472],{"class":455},"    \"",[110,474,476],{"class":475},"sZMiF","dev",[110,478,213],{"class":455},[110,480,465],{"class":131},[110,482,483],{"class":212}," \"",[110,485,486],{"class":127},"nodemon app.js",[110,488,489],{"class":212},"\"\n",[110,491,492],{"class":112,"line":155},[110,493,494],{"class":131},"  }\n",[110,496,497],{"class":112,"line":162},[110,498,499],{"class":131},"}\n",[22,501,502,503,506],{},"运行 ",[107,504,505],{},"npm run dev"," 即可在代码变更后自动重启服务器。",[47,508,510],{"id":509},"三请求对象request-object","三、请求对象（Request Object）",[22,512,513,514,516],{},"请求对象（",[107,515,288],{},"）包含了客户端发送的所有 HTTP 请求信息，是应用处理请求的重要依据。",[518,519,520,536],"table",{},[521,522,523],"thead",{},[524,525,526,530,533],"tr",{},[527,528,529],"th",{},"属性\u002F方法",[527,531,532],{},"说明",[527,534,535],{},"示例",[537,538,539,560,579,595,610,636],"tbody",{},[524,540,541,547,550],{},[542,543,544],"td",{},[107,545,546],{},"req.params",[542,548,549],{},"获取路由路径中的动态参数",[542,551,552,555,556,559],{},[107,553,554],{},"req.params.id","（路由 ",[107,557,558],{},"\u002F:id","）",[524,561,562,567,570],{},[542,563,564],{},[107,565,566],{},"req.query",[542,568,569],{},"获取 URL 查询字符串参数",[542,571,572,575,576,559],{},[107,573,574],{},"req.query.page","（",[107,577,578],{},"?page=2",[524,580,581,586,589],{},[542,582,583],{},[107,584,585],{},"req.body",[542,587,588],{},"获取 POST\u002FPUT 请求体中的参数",[542,590,591,594],{},[107,592,593],{},"req.body.username","（需配合中间件）",[524,596,597,602,605],{},[542,598,599],{},[107,600,601],{},"req.headers",[542,603,604],{},"获取客户端发送的 HTTP 头信息",[542,606,607],{},[107,608,609],{},"req.headers['content-type']",[524,611,612,617,620],{},[542,613,614],{},[107,615,616],{},"req.method",[542,618,619],{},"获取 HTTP 请求方法",[542,621,622,625,626,625,629,625,632,635],{},[107,623,624],{},"GET",", ",[107,627,628],{},"POST",[107,630,631],{},"PUT",[107,633,634],{},"DELETE"," 等",[524,637,638,643,646],{},[542,639,640],{},[107,641,642],{},"req.url",[542,644,645],{},"获取请求的 URL 路径",[542,647,648],{},[107,649,650],{},"\u002Fapi\u002Fusers",[22,652,653],{},"各属性的详细用法：",[100,655,657],{"className":183,"code":656,"language":185,"meta":105,"style":105},"\u002F\u002F 路由参数 params: GET \u002Fuser\u002F123 -> { id: '123' }\napp.get(\"\u002Fuser\u002F:id\", (req, res) => {\n  console.log(req.params.id);\n});\n\n\u002F\u002F 查询参数 query: GET \u002Fsearch?q=express&page=1 -> { q: 'express', page: '1' }\napp.get(\"\u002Fsearch\", (req, res) => {\n  console.log(req.query.q);\n});\n\n\u002F\u002F 请求体 body: 需要 express.json() 或 express.urlencoded() 中间件\napp.post(\"\u002Flogin\", (req, res) => {\n  console.log(req.body.username);\n});\n\n\u002F\u002F 请求头 headers\napp.get(\"\u002Finfo\", (req, res) => {\n  console.log(req.headers[\"user-agent\"]);\n});\n",[107,658,659,664,697,723,731,735,740,773,799,807,811,816,851,878,887,892,898,932,965],{"__ignoreMap":105},[110,660,661],{"class":112,"line":113},[110,662,663],{"class":116},"\u002F\u002F 路由参数 params: GET \u002Fuser\u002F123 -> { id: '123' }\n",[110,665,666,668,670,672,674,676,679,681,683,685,687,689,691,693,695],{"class":112,"line":120},[110,667,263],{"class":208},[110,669,266],{"class":131},[110,671,269],{"class":204},[110,673,209],{"class":208},[110,675,213],{"class":212},[110,677,678],{"class":127},"\u002Fuser\u002F:id",[110,680,213],{"class":212},[110,682,281],{"class":131},[110,684,284],{"class":131},[110,686,288],{"class":287},[110,688,281],{"class":131},[110,690,293],{"class":287},[110,692,220],{"class":131},[110,694,298],{"class":192},[110,696,301],{"class":131},[110,698,699,701,703,705,707,709,711,714,716,719,721],{"class":112,"line":142},[110,700,368],{"class":208},[110,702,266],{"class":131},[110,704,373],{"class":204},[110,706,209],{"class":314},[110,708,288],{"class":208},[110,710,266],{"class":131},[110,712,713],{"class":208},"params",[110,715,266],{"class":131},[110,717,718],{"class":208},"id",[110,720,220],{"class":314},[110,722,223],{"class":131},[110,724,725,727,729],{"class":112,"line":155},[110,726,331],{"class":131},[110,728,220],{"class":208},[110,730,223],{"class":131},[110,732,733],{"class":112,"line":162},[110,734,159],{"emptyLinePlaceholder":158},[110,736,737],{"class":112,"line":168},[110,738,739],{"class":116},"\u002F\u002F 查询参数 query: GET \u002Fsearch?q=express&page=1 -> { q: 'express', page: '1' }\n",[110,741,742,744,746,748,750,752,755,757,759,761,763,765,767,769,771],{"class":112,"line":328},[110,743,263],{"class":208},[110,745,266],{"class":131},[110,747,269],{"class":204},[110,749,209],{"class":208},[110,751,213],{"class":212},[110,753,754],{"class":127},"\u002Fsearch",[110,756,213],{"class":212},[110,758,281],{"class":131},[110,760,284],{"class":131},[110,762,288],{"class":287},[110,764,281],{"class":131},[110,766,293],{"class":287},[110,768,220],{"class":131},[110,770,298],{"class":192},[110,772,301],{"class":131},[110,774,775,777,779,781,783,785,787,790,792,795,797],{"class":112,"line":338},[110,776,368],{"class":208},[110,778,266],{"class":131},[110,780,373],{"class":204},[110,782,209],{"class":314},[110,784,288],{"class":208},[110,786,266],{"class":131},[110,788,789],{"class":208},"query",[110,791,266],{"class":131},[110,793,794],{"class":208},"q",[110,796,220],{"class":314},[110,798,223],{"class":131},[110,800,801,803,805],{"class":112,"line":343},[110,802,331],{"class":131},[110,804,220],{"class":208},[110,806,223],{"class":131},[110,808,809],{"class":112,"line":365},[110,810,159],{"emptyLinePlaceholder":158},[110,812,813],{"class":112,"line":397},[110,814,815],{"class":116},"\u002F\u002F 请求体 body: 需要 express.json() 或 express.urlencoded() 中间件\n",[110,817,819,821,823,826,828,830,833,835,837,839,841,843,845,847,849],{"class":112,"line":818},12,[110,820,263],{"class":208},[110,822,266],{"class":131},[110,824,825],{"class":204},"post",[110,827,209],{"class":208},[110,829,213],{"class":212},[110,831,832],{"class":127},"\u002Flogin",[110,834,213],{"class":212},[110,836,281],{"class":131},[110,838,284],{"class":131},[110,840,288],{"class":287},[110,842,281],{"class":131},[110,844,293],{"class":287},[110,846,220],{"class":131},[110,848,298],{"class":192},[110,850,301],{"class":131},[110,852,854,856,858,860,862,864,866,869,871,874,876],{"class":112,"line":853},13,[110,855,368],{"class":208},[110,857,266],{"class":131},[110,859,373],{"class":204},[110,861,209],{"class":314},[110,863,288],{"class":208},[110,865,266],{"class":131},[110,867,868],{"class":208},"body",[110,870,266],{"class":131},[110,872,873],{"class":208},"username",[110,875,220],{"class":314},[110,877,223],{"class":131},[110,879,881,883,885],{"class":112,"line":880},14,[110,882,331],{"class":131},[110,884,220],{"class":208},[110,886,223],{"class":131},[110,888,890],{"class":112,"line":889},15,[110,891,159],{"emptyLinePlaceholder":158},[110,893,895],{"class":112,"line":894},16,[110,896,897],{"class":116},"\u002F\u002F 请求头 headers\n",[110,899,901,903,905,907,909,911,914,916,918,920,922,924,926,928,930],{"class":112,"line":900},17,[110,902,263],{"class":208},[110,904,266],{"class":131},[110,906,269],{"class":204},[110,908,209],{"class":208},[110,910,213],{"class":212},[110,912,913],{"class":127},"\u002Finfo",[110,915,213],{"class":212},[110,917,281],{"class":131},[110,919,284],{"class":131},[110,921,288],{"class":287},[110,923,281],{"class":131},[110,925,293],{"class":287},[110,927,220],{"class":131},[110,929,298],{"class":192},[110,931,301],{"class":131},[110,933,935,937,939,941,943,945,947,950,953,955,958,960,963],{"class":112,"line":934},18,[110,936,368],{"class":208},[110,938,266],{"class":131},[110,940,373],{"class":204},[110,942,209],{"class":314},[110,944,288],{"class":208},[110,946,266],{"class":131},[110,948,949],{"class":208},"headers",[110,951,952],{"class":314},"[",[110,954,213],{"class":212},[110,956,957],{"class":127},"user-agent",[110,959,213],{"class":212},[110,961,962],{"class":314},"])",[110,964,223],{"class":131},[110,966,968,970,972],{"class":112,"line":967},19,[110,969,331],{"class":131},[110,971,220],{"class":208},[110,973,223],{"class":131},[975,976,977],"blockquote",{},[22,978,979,982,983,985,986,989,990,45],{},[32,980,981],{},"注意","：若要使用 ",[107,984,585],{},"，必须先应用解析请求体的中间件，如 ",[107,987,988],{},"express.json()"," 或 ",[107,991,992],{},"express.urlencoded()",[47,994,996],{"id":995},"四响应对象response-object","四、响应对象（Response Object）",[22,998,999,1000,1003],{},"响应对象（",[107,1001,1002],{},"res","）用于向客户端返回数据。以下是最常用的响应方法：",[518,1005,1006,1017],{},[521,1007,1008],{},[524,1009,1010,1013,1015],{},[527,1011,1012],{},"方法",[527,1014,532],{},[527,1016,535],{},[537,1018,1019,1034,1052,1067,1082,1097,1112],{},[524,1020,1021,1026,1029],{},[542,1022,1023],{},[107,1024,1025],{},"res.send()",[542,1027,1028],{},"发送各种类型的响应（字符串、对象、Buffer 等）",[542,1030,1031],{},[107,1032,1033],{},"res.send('Hello')",[524,1035,1036,1041,1047],{},[542,1037,1038],{},[107,1039,1040],{},"res.json()",[542,1042,1043,1044],{},"发送 JSON 格式响应，自动设置 ",[107,1045,1046],{},"Content-Type: application\u002Fjson",[542,1048,1049],{},[107,1050,1051],{},"res.json({ name: 'John' })",[524,1053,1054,1059,1062],{},[542,1055,1056],{},[107,1057,1058],{},"res.status()",[542,1060,1061],{},"设置 HTTP 状态码，支持链式调用",[542,1063,1064],{},[107,1065,1066],{},"res.status(201).send('Created')",[524,1068,1069,1074,1077],{},[542,1070,1071],{},[107,1072,1073],{},"res.redirect()",[542,1075,1076],{},"重定向到指定 URL",[542,1078,1079],{},[107,1080,1081],{},"res.redirect('\u002Flogin')",[524,1083,1084,1089,1092],{},[542,1085,1086],{},[107,1087,1088],{},"res.render()",[542,1090,1091],{},"渲染模板引擎（需配置）",[542,1093,1094],{},[107,1095,1096],{},"res.render('index', { title: '主页' })",[524,1098,1099,1104,1107],{},[542,1100,1101],{},[107,1102,1103],{},"res.sendFile()",[542,1105,1106],{},"发送文件（用于文件下载）",[542,1108,1109],{},[107,1110,1111],{},"res.sendFile(path.join(__dirname, 'file.pdf'))",[524,1113,1114,1119,1122],{},[542,1115,1116],{},[107,1117,1118],{},"res.sendStatus()",[542,1120,1121],{},"设置状态码并发送其对应的文本描述",[542,1123,1124,1127],{},[107,1125,1126],{},"res.sendStatus(404)","→'Not Found'",[22,1129,1130],{},"各方法的详细用法：",[100,1132,1134],{"className":183,"code":1133,"language":185,"meta":105,"style":105},"\u002F\u002F 发送纯文本\napp.get(\"\u002F\", (req, res) => {\n  res.send(\"Hello World!\");\n});\n\n\u002F\u002F 发送 JSON\napp.get(\"\u002Fapi\u002Fuser\", (req, res) => {\n  res.json({ id: 1, name: \"Alice\" });\n});\n\n\u002F\u002F 链式调用：先设置状态码，再发送响应\napp.post(\"\u002Fapi\u002Fuser\", (req, res) => {\n  res.status(201).json({ message: \"用户创建成功\" });\n});\n\n\u002F\u002F 重定向\napp.get(\"\u002Fold\", (req, res) => {\n  res.redirect(\"\u002Fnew\");\n});\n",[107,1135,1136,1141,1173,1193,1201,1205,1210,1243,1285,1293,1297,1302,1334,1376,1384,1388,1393,1426,1448],{"__ignoreMap":105},[110,1137,1138],{"class":112,"line":113},[110,1139,1140],{"class":116},"\u002F\u002F 发送纯文本\n",[110,1142,1143,1145,1147,1149,1151,1153,1155,1157,1159,1161,1163,1165,1167,1169,1171],{"class":112,"line":120},[110,1144,263],{"class":208},[110,1146,266],{"class":131},[110,1148,269],{"class":204},[110,1150,209],{"class":208},[110,1152,213],{"class":212},[110,1154,276],{"class":127},[110,1156,213],{"class":212},[110,1158,281],{"class":131},[110,1160,284],{"class":131},[110,1162,288],{"class":287},[110,1164,281],{"class":131},[110,1166,293],{"class":287},[110,1168,220],{"class":131},[110,1170,298],{"class":192},[110,1172,301],{"class":131},[110,1174,1175,1177,1179,1181,1183,1185,1187,1189,1191],{"class":112,"line":142},[110,1176,306],{"class":208},[110,1178,266],{"class":131},[110,1180,311],{"class":204},[110,1182,209],{"class":314},[110,1184,213],{"class":212},[110,1186,319],{"class":127},[110,1188,213],{"class":212},[110,1190,220],{"class":314},[110,1192,223],{"class":131},[110,1194,1195,1197,1199],{"class":112,"line":155},[110,1196,331],{"class":131},[110,1198,220],{"class":208},[110,1200,223],{"class":131},[110,1202,1203],{"class":112,"line":162},[110,1204,159],{"emptyLinePlaceholder":158},[110,1206,1207],{"class":112,"line":168},[110,1208,1209],{"class":116},"\u002F\u002F 发送 JSON\n",[110,1211,1212,1214,1216,1218,1220,1222,1225,1227,1229,1231,1233,1235,1237,1239,1241],{"class":112,"line":328},[110,1213,263],{"class":208},[110,1215,266],{"class":131},[110,1217,269],{"class":204},[110,1219,209],{"class":208},[110,1221,213],{"class":212},[110,1223,1224],{"class":127},"\u002Fapi\u002Fuser",[110,1226,213],{"class":212},[110,1228,281],{"class":131},[110,1230,284],{"class":131},[110,1232,288],{"class":287},[110,1234,281],{"class":131},[110,1236,293],{"class":287},[110,1238,220],{"class":131},[110,1240,298],{"class":192},[110,1242,301],{"class":131},[110,1244,1245,1247,1249,1251,1253,1256,1259,1261,1264,1266,1269,1271,1273,1276,1278,1281,1283],{"class":112,"line":338},[110,1246,306],{"class":208},[110,1248,266],{"class":131},[110,1250,443],{"class":204},[110,1252,209],{"class":314},[110,1254,1255],{"class":131},"{",[110,1257,1258],{"class":314}," id",[110,1260,465],{"class":131},[110,1262,1263],{"class":251}," 1",[110,1265,281],{"class":131},[110,1267,1268],{"class":314}," name",[110,1270,465],{"class":131},[110,1272,483],{"class":212},[110,1274,1275],{"class":127},"Alice",[110,1277,213],{"class":212},[110,1279,1280],{"class":131}," }",[110,1282,220],{"class":314},[110,1284,223],{"class":131},[110,1286,1287,1289,1291],{"class":112,"line":343},[110,1288,331],{"class":131},[110,1290,220],{"class":208},[110,1292,223],{"class":131},[110,1294,1295],{"class":112,"line":365},[110,1296,159],{"emptyLinePlaceholder":158},[110,1298,1299],{"class":112,"line":397},[110,1300,1301],{"class":116},"\u002F\u002F 链式调用：先设置状态码，再发送响应\n",[110,1303,1304,1306,1308,1310,1312,1314,1316,1318,1320,1322,1324,1326,1328,1330,1332],{"class":112,"line":818},[110,1305,263],{"class":208},[110,1307,266],{"class":131},[110,1309,825],{"class":204},[110,1311,209],{"class":208},[110,1313,213],{"class":212},[110,1315,1224],{"class":127},[110,1317,213],{"class":212},[110,1319,281],{"class":131},[110,1321,284],{"class":131},[110,1323,288],{"class":287},[110,1325,281],{"class":131},[110,1327,293],{"class":287},[110,1329,220],{"class":131},[110,1331,298],{"class":192},[110,1333,301],{"class":131},[110,1335,1336,1338,1340,1343,1345,1348,1350,1352,1354,1356,1358,1361,1363,1365,1368,1370,1372,1374],{"class":112,"line":853},[110,1337,306],{"class":208},[110,1339,266],{"class":131},[110,1341,1342],{"class":204},"status",[110,1344,209],{"class":314},[110,1346,1347],{"class":251},"201",[110,1349,220],{"class":314},[110,1351,266],{"class":131},[110,1353,443],{"class":204},[110,1355,209],{"class":314},[110,1357,1255],{"class":131},[110,1359,1360],{"class":314}," message",[110,1362,465],{"class":131},[110,1364,483],{"class":212},[110,1366,1367],{"class":127},"用户创建成功",[110,1369,213],{"class":212},[110,1371,1280],{"class":131},[110,1373,220],{"class":314},[110,1375,223],{"class":131},[110,1377,1378,1380,1382],{"class":112,"line":880},[110,1379,331],{"class":131},[110,1381,220],{"class":208},[110,1383,223],{"class":131},[110,1385,1386],{"class":112,"line":889},[110,1387,159],{"emptyLinePlaceholder":158},[110,1389,1390],{"class":112,"line":894},[110,1391,1392],{"class":116},"\u002F\u002F 重定向\n",[110,1394,1395,1397,1399,1401,1403,1405,1408,1410,1412,1414,1416,1418,1420,1422,1424],{"class":112,"line":900},[110,1396,263],{"class":208},[110,1398,266],{"class":131},[110,1400,269],{"class":204},[110,1402,209],{"class":208},[110,1404,213],{"class":212},[110,1406,1407],{"class":127},"\u002Fold",[110,1409,213],{"class":212},[110,1411,281],{"class":131},[110,1413,284],{"class":131},[110,1415,288],{"class":287},[110,1417,281],{"class":131},[110,1419,293],{"class":287},[110,1421,220],{"class":131},[110,1423,298],{"class":192},[110,1425,301],{"class":131},[110,1427,1428,1430,1432,1435,1437,1439,1442,1444,1446],{"class":112,"line":934},[110,1429,306],{"class":208},[110,1431,266],{"class":131},[110,1433,1434],{"class":204},"redirect",[110,1436,209],{"class":314},[110,1438,213],{"class":212},[110,1440,1441],{"class":127},"\u002Fnew",[110,1443,213],{"class":212},[110,1445,220],{"class":314},[110,1447,223],{"class":131},[110,1449,1450,1452,1454],{"class":112,"line":967},[110,1451,331],{"class":131},[110,1453,220],{"class":208},[110,1455,223],{"class":131},[47,1457,1459],{"id":1458},"五路由routing","五、路由（Routing）",[22,1461,1462],{},"路由是 Express 的核心功能之一，它将 HTTP 方法、URL 路径与处理函数关联起来。",[95,1464,1466],{"id":1465},"_1-基本路由","1. 基本路由",[100,1468,1470],{"className":183,"code":1469,"language":185,"meta":105,"style":105},"\u002F\u002F GET 请求\napp.get(\"\u002F\", (req, res) => {\n  res.send(\"收到 GET 请求\");\n});\n\n\u002F\u002F POST 请求\napp.post(\"\u002Fuser\", (req, res) => {\n  res.send(\"收到 POST 请求\");\n});\n\n\u002F\u002F PUT 请求\napp.put(\"\u002Fuser\u002F:id\", (req, res) => {\n  res.send(`更新用户 ${req.params.id}`);\n});\n\n\u002F\u002F DELETE 请求\napp.delete(\"\u002Fuser\u002F:id\", (req, res) => {\n  res.send(`删除用户 ${req.params.id}`);\n});\n\n\u002F\u002F 处理所有 HTTP 方法（常用于全局中间件）\napp.all(\"\u002Fsecret\", (req, res, next) => {\n  console.log(\"访问了秘密路径\");\n  next();\n});\n",[107,1471,1472,1477,1509,1530,1538,1542,1547,1580,1601,1609,1613,1618,1651,1684,1692,1696,1701,1734,1767,1775,1780,1786,1826,1848,1858],{"__ignoreMap":105},[110,1473,1474],{"class":112,"line":113},[110,1475,1476],{"class":116},"\u002F\u002F GET 请求\n",[110,1478,1479,1481,1483,1485,1487,1489,1491,1493,1495,1497,1499,1501,1503,1505,1507],{"class":112,"line":120},[110,1480,263],{"class":208},[110,1482,266],{"class":131},[110,1484,269],{"class":204},[110,1486,209],{"class":208},[110,1488,213],{"class":212},[110,1490,276],{"class":127},[110,1492,213],{"class":212},[110,1494,281],{"class":131},[110,1496,284],{"class":131},[110,1498,288],{"class":287},[110,1500,281],{"class":131},[110,1502,293],{"class":287},[110,1504,220],{"class":131},[110,1506,298],{"class":192},[110,1508,301],{"class":131},[110,1510,1511,1513,1515,1517,1519,1521,1524,1526,1528],{"class":112,"line":142},[110,1512,306],{"class":208},[110,1514,266],{"class":131},[110,1516,311],{"class":204},[110,1518,209],{"class":314},[110,1520,213],{"class":212},[110,1522,1523],{"class":127},"收到 GET 请求",[110,1525,213],{"class":212},[110,1527,220],{"class":314},[110,1529,223],{"class":131},[110,1531,1532,1534,1536],{"class":112,"line":155},[110,1533,331],{"class":131},[110,1535,220],{"class":208},[110,1537,223],{"class":131},[110,1539,1540],{"class":112,"line":162},[110,1541,159],{"emptyLinePlaceholder":158},[110,1543,1544],{"class":112,"line":168},[110,1545,1546],{"class":116},"\u002F\u002F POST 请求\n",[110,1548,1549,1551,1553,1555,1557,1559,1562,1564,1566,1568,1570,1572,1574,1576,1578],{"class":112,"line":328},[110,1550,263],{"class":208},[110,1552,266],{"class":131},[110,1554,825],{"class":204},[110,1556,209],{"class":208},[110,1558,213],{"class":212},[110,1560,1561],{"class":127},"\u002Fuser",[110,1563,213],{"class":212},[110,1565,281],{"class":131},[110,1567,284],{"class":131},[110,1569,288],{"class":287},[110,1571,281],{"class":131},[110,1573,293],{"class":287},[110,1575,220],{"class":131},[110,1577,298],{"class":192},[110,1579,301],{"class":131},[110,1581,1582,1584,1586,1588,1590,1592,1595,1597,1599],{"class":112,"line":338},[110,1583,306],{"class":208},[110,1585,266],{"class":131},[110,1587,311],{"class":204},[110,1589,209],{"class":314},[110,1591,213],{"class":212},[110,1593,1594],{"class":127},"收到 POST 请求",[110,1596,213],{"class":212},[110,1598,220],{"class":314},[110,1600,223],{"class":131},[110,1602,1603,1605,1607],{"class":112,"line":343},[110,1604,331],{"class":131},[110,1606,220],{"class":208},[110,1608,223],{"class":131},[110,1610,1611],{"class":112,"line":365},[110,1612,159],{"emptyLinePlaceholder":158},[110,1614,1615],{"class":112,"line":397},[110,1616,1617],{"class":116},"\u002F\u002F PUT 请求\n",[110,1619,1620,1622,1624,1627,1629,1631,1633,1635,1637,1639,1641,1643,1645,1647,1649],{"class":112,"line":818},[110,1621,263],{"class":208},[110,1623,266],{"class":131},[110,1625,1626],{"class":204},"put",[110,1628,209],{"class":208},[110,1630,213],{"class":212},[110,1632,678],{"class":127},[110,1634,213],{"class":212},[110,1636,281],{"class":131},[110,1638,284],{"class":131},[110,1640,288],{"class":287},[110,1642,281],{"class":131},[110,1644,293],{"class":287},[110,1646,220],{"class":131},[110,1648,298],{"class":192},[110,1650,301],{"class":131},[110,1652,1653,1655,1657,1659,1661,1663,1666,1668,1670,1672,1674,1676,1678,1680,1682],{"class":112,"line":853},[110,1654,306],{"class":208},[110,1656,266],{"class":131},[110,1658,311],{"class":204},[110,1660,209],{"class":314},[110,1662,378],{"class":212},[110,1664,1665],{"class":127},"更新用户 ",[110,1667,384],{"class":212},[110,1669,288],{"class":208},[110,1671,266],{"class":212},[110,1673,713],{"class":208},[110,1675,266],{"class":212},[110,1677,718],{"class":208},[110,1679,390],{"class":212},[110,1681,220],{"class":314},[110,1683,223],{"class":131},[110,1685,1686,1688,1690],{"class":112,"line":880},[110,1687,331],{"class":131},[110,1689,220],{"class":208},[110,1691,223],{"class":131},[110,1693,1694],{"class":112,"line":889},[110,1695,159],{"emptyLinePlaceholder":158},[110,1697,1698],{"class":112,"line":894},[110,1699,1700],{"class":116},"\u002F\u002F DELETE 请求\n",[110,1702,1703,1705,1707,1710,1712,1714,1716,1718,1720,1722,1724,1726,1728,1730,1732],{"class":112,"line":900},[110,1704,263],{"class":208},[110,1706,266],{"class":131},[110,1708,1709],{"class":204},"delete",[110,1711,209],{"class":208},[110,1713,213],{"class":212},[110,1715,678],{"class":127},[110,1717,213],{"class":212},[110,1719,281],{"class":131},[110,1721,284],{"class":131},[110,1723,288],{"class":287},[110,1725,281],{"class":131},[110,1727,293],{"class":287},[110,1729,220],{"class":131},[110,1731,298],{"class":192},[110,1733,301],{"class":131},[110,1735,1736,1738,1740,1742,1744,1746,1749,1751,1753,1755,1757,1759,1761,1763,1765],{"class":112,"line":934},[110,1737,306],{"class":208},[110,1739,266],{"class":131},[110,1741,311],{"class":204},[110,1743,209],{"class":314},[110,1745,378],{"class":212},[110,1747,1748],{"class":127},"删除用户 ",[110,1750,384],{"class":212},[110,1752,288],{"class":208},[110,1754,266],{"class":212},[110,1756,713],{"class":208},[110,1758,266],{"class":212},[110,1760,718],{"class":208},[110,1762,390],{"class":212},[110,1764,220],{"class":314},[110,1766,223],{"class":131},[110,1768,1769,1771,1773],{"class":112,"line":967},[110,1770,331],{"class":131},[110,1772,220],{"class":208},[110,1774,223],{"class":131},[110,1776,1778],{"class":112,"line":1777},20,[110,1779,159],{"emptyLinePlaceholder":158},[110,1781,1783],{"class":112,"line":1782},21,[110,1784,1785],{"class":116},"\u002F\u002F 处理所有 HTTP 方法（常用于全局中间件）\n",[110,1787,1789,1791,1793,1796,1798,1800,1803,1805,1807,1809,1811,1813,1815,1817,1820,1822,1824],{"class":112,"line":1788},22,[110,1790,263],{"class":208},[110,1792,266],{"class":131},[110,1794,1795],{"class":204},"all",[110,1797,209],{"class":208},[110,1799,213],{"class":212},[110,1801,1802],{"class":127},"\u002Fsecret",[110,1804,213],{"class":212},[110,1806,281],{"class":131},[110,1808,284],{"class":131},[110,1810,288],{"class":287},[110,1812,281],{"class":131},[110,1814,293],{"class":287},[110,1816,281],{"class":131},[110,1818,1819],{"class":287}," next",[110,1821,220],{"class":131},[110,1823,298],{"class":192},[110,1825,301],{"class":131},[110,1827,1829,1831,1833,1835,1837,1839,1842,1844,1846],{"class":112,"line":1828},23,[110,1830,368],{"class":208},[110,1832,266],{"class":131},[110,1834,373],{"class":204},[110,1836,209],{"class":314},[110,1838,213],{"class":212},[110,1840,1841],{"class":127},"访问了秘密路径",[110,1843,213],{"class":212},[110,1845,220],{"class":314},[110,1847,223],{"class":131},[110,1849,1851,1854,1856],{"class":112,"line":1850},24,[110,1852,1853],{"class":204},"  next",[110,1855,237],{"class":314},[110,1857,223],{"class":131},[110,1859,1861,1863,1865],{"class":112,"line":1860},25,[110,1862,331],{"class":131},[110,1864,220],{"class":208},[110,1866,223],{"class":131},[95,1868,1870],{"id":1869},"_2-路由参数","2. 路由参数",[100,1872,1874],{"className":183,"code":1873,"language":185,"meta":105,"style":105},"\u002F\u002F 单个参数\napp.get(\"\u002Fusers\u002F:userId\", (req, res) => {\n  res.send(`用户 ID: ${req.params.userId}`);\n});\n\n\u002F\u002F 多个参数\napp.get(\"\u002Fposts\u002F:postId\u002Fcomments\u002F:commentId\", (req, res) => {\n  res.send(`帖子 ${req.params.postId}，评论 ${req.params.commentId}`);\n});\n",[107,1875,1876,1881,1914,1948,1956,1960,1965,1998,2050],{"__ignoreMap":105},[110,1877,1878],{"class":112,"line":113},[110,1879,1880],{"class":116},"\u002F\u002F 单个参数\n",[110,1882,1883,1885,1887,1889,1891,1893,1896,1898,1900,1902,1904,1906,1908,1910,1912],{"class":112,"line":120},[110,1884,263],{"class":208},[110,1886,266],{"class":131},[110,1888,269],{"class":204},[110,1890,209],{"class":208},[110,1892,213],{"class":212},[110,1894,1895],{"class":127},"\u002Fusers\u002F:userId",[110,1897,213],{"class":212},[110,1899,281],{"class":131},[110,1901,284],{"class":131},[110,1903,288],{"class":287},[110,1905,281],{"class":131},[110,1907,293],{"class":287},[110,1909,220],{"class":131},[110,1911,298],{"class":192},[110,1913,301],{"class":131},[110,1915,1916,1918,1920,1922,1924,1926,1929,1931,1933,1935,1937,1939,1942,1944,1946],{"class":112,"line":142},[110,1917,306],{"class":208},[110,1919,266],{"class":131},[110,1921,311],{"class":204},[110,1923,209],{"class":314},[110,1925,378],{"class":212},[110,1927,1928],{"class":127},"用户 ID: ",[110,1930,384],{"class":212},[110,1932,288],{"class":208},[110,1934,266],{"class":212},[110,1936,713],{"class":208},[110,1938,266],{"class":212},[110,1940,1941],{"class":208},"userId",[110,1943,390],{"class":212},[110,1945,220],{"class":314},[110,1947,223],{"class":131},[110,1949,1950,1952,1954],{"class":112,"line":155},[110,1951,331],{"class":131},[110,1953,220],{"class":208},[110,1955,223],{"class":131},[110,1957,1958],{"class":112,"line":162},[110,1959,159],{"emptyLinePlaceholder":158},[110,1961,1962],{"class":112,"line":168},[110,1963,1964],{"class":116},"\u002F\u002F 多个参数\n",[110,1966,1967,1969,1971,1973,1975,1977,1980,1982,1984,1986,1988,1990,1992,1994,1996],{"class":112,"line":328},[110,1968,263],{"class":208},[110,1970,266],{"class":131},[110,1972,269],{"class":204},[110,1974,209],{"class":208},[110,1976,213],{"class":212},[110,1978,1979],{"class":127},"\u002Fposts\u002F:postId\u002Fcomments\u002F:commentId",[110,1981,213],{"class":212},[110,1983,281],{"class":131},[110,1985,284],{"class":131},[110,1987,288],{"class":287},[110,1989,281],{"class":131},[110,1991,293],{"class":287},[110,1993,220],{"class":131},[110,1995,298],{"class":192},[110,1997,301],{"class":131},[110,1999,2000,2002,2004,2006,2008,2010,2013,2015,2017,2019,2021,2023,2026,2028,2031,2033,2035,2037,2039,2041,2044,2046,2048],{"class":112,"line":338},[110,2001,306],{"class":208},[110,2003,266],{"class":131},[110,2005,311],{"class":204},[110,2007,209],{"class":314},[110,2009,378],{"class":212},[110,2011,2012],{"class":127},"帖子 ",[110,2014,384],{"class":212},[110,2016,288],{"class":208},[110,2018,266],{"class":212},[110,2020,713],{"class":208},[110,2022,266],{"class":212},[110,2024,2025],{"class":208},"postId",[110,2027,331],{"class":212},[110,2029,2030],{"class":127},"，评论 ",[110,2032,384],{"class":212},[110,2034,288],{"class":208},[110,2036,266],{"class":212},[110,2038,713],{"class":208},[110,2040,266],{"class":212},[110,2042,2043],{"class":208},"commentId",[110,2045,390],{"class":212},[110,2047,220],{"class":314},[110,2049,223],{"class":131},[110,2051,2052,2054,2056],{"class":112,"line":343},[110,2053,331],{"class":131},[110,2055,220],{"class":208},[110,2057,223],{"class":131},[95,2059,2061,2062,2065],{"id":2060},"_3-expressrouter-模块化路由推荐用于项目结构","3. ",[107,2063,2064],{},"express.Router"," 模块化路由（推荐用于项目结构）",[22,2067,2068,2069,2071],{},"随着应用规模增长，将所有路由写在同一个文件中会导致代码难以维护。",[107,2070,2064],{}," 允许将相关的路由分组并导出，实现代码的模块化。",[100,2073,2075],{"className":183,"code":2074,"language":185,"meta":105,"style":105},"\u002F\u002F routes\u002Fusers.js 文件\nconst express = require(\"express\");\nconst router = express.Router();\n\n\u002F\u002F 该路由下的中间件（仅对此模块生效）\nrouter.use((req, res, next) => {\n  console.log(`[Users] ${req.method} ${req.path}`);\n  next();\n});\n\nrouter.get(\"\u002F\", (req, res) => {\n  res.json({ users: [\"Alice\", \"Bob\"] });\n});\n\nrouter.get(\"\u002F:id\", (req, res) => {\n  res.json({ userId: req.params.id });\n});\n\nrouter.post(\"\u002F\", (req, res) => {\n  res.status(201).json({ message: \"用户创建成功\" });\n});\n\nmodule.exports = router;\n",[107,2076,2077,2082,2104,2124,2128,2133,2163,2205,2213,2221,2225,2257,2301,2309,2313,2345,2379,2387,2391,2423,2461,2469,2473],{"__ignoreMap":105},[110,2078,2079],{"class":112,"line":113},[110,2080,2081],{"class":116},"\u002F\u002F routes\u002Fusers.js 文件\n",[110,2083,2084,2086,2088,2090,2092,2094,2096,2098,2100,2102],{"class":112,"line":120},[110,2085,193],{"class":192},[110,2087,197],{"class":196},[110,2089,201],{"class":200},[110,2091,205],{"class":204},[110,2093,209],{"class":208},[110,2095,213],{"class":212},[110,2097,12],{"class":127},[110,2099,213],{"class":212},[110,2101,220],{"class":208},[110,2103,223],{"class":131},[110,2105,2106,2108,2111,2113,2115,2117,2120,2122],{"class":112,"line":142},[110,2107,193],{"class":192},[110,2109,2110],{"class":196}," router",[110,2112,201],{"class":200},[110,2114,197],{"class":208},[110,2116,266],{"class":131},[110,2118,2119],{"class":204},"Router",[110,2121,237],{"class":208},[110,2123,223],{"class":131},[110,2125,2126],{"class":112,"line":155},[110,2127,159],{"emptyLinePlaceholder":158},[110,2129,2130],{"class":112,"line":162},[110,2131,2132],{"class":116},"\u002F\u002F 该路由下的中间件（仅对此模块生效）\n",[110,2134,2135,2138,2140,2143,2145,2147,2149,2151,2153,2155,2157,2159,2161],{"class":112,"line":168},[110,2136,2137],{"class":208},"router",[110,2139,266],{"class":131},[110,2141,2142],{"class":204},"use",[110,2144,209],{"class":208},[110,2146,209],{"class":131},[110,2148,288],{"class":287},[110,2150,281],{"class":131},[110,2152,293],{"class":287},[110,2154,281],{"class":131},[110,2156,1819],{"class":287},[110,2158,220],{"class":131},[110,2160,298],{"class":192},[110,2162,301],{"class":131},[110,2164,2165,2167,2169,2171,2173,2175,2178,2180,2182,2184,2187,2189,2192,2194,2196,2199,2201,2203],{"class":112,"line":328},[110,2166,368],{"class":208},[110,2168,266],{"class":131},[110,2170,373],{"class":204},[110,2172,209],{"class":314},[110,2174,378],{"class":212},[110,2176,2177],{"class":127},"[Users] ",[110,2179,384],{"class":212},[110,2181,288],{"class":208},[110,2183,266],{"class":212},[110,2185,2186],{"class":208},"method",[110,2188,331],{"class":212},[110,2190,2191],{"class":212}," ${",[110,2193,288],{"class":208},[110,2195,266],{"class":212},[110,2197,2198],{"class":208},"path",[110,2200,390],{"class":212},[110,2202,220],{"class":314},[110,2204,223],{"class":131},[110,2206,2207,2209,2211],{"class":112,"line":338},[110,2208,1853],{"class":204},[110,2210,237],{"class":314},[110,2212,223],{"class":131},[110,2214,2215,2217,2219],{"class":112,"line":343},[110,2216,331],{"class":131},[110,2218,220],{"class":208},[110,2220,223],{"class":131},[110,2222,2223],{"class":112,"line":365},[110,2224,159],{"emptyLinePlaceholder":158},[110,2226,2227,2229,2231,2233,2235,2237,2239,2241,2243,2245,2247,2249,2251,2253,2255],{"class":112,"line":397},[110,2228,2137],{"class":208},[110,2230,266],{"class":131},[110,2232,269],{"class":204},[110,2234,209],{"class":208},[110,2236,213],{"class":212},[110,2238,276],{"class":127},[110,2240,213],{"class":212},[110,2242,281],{"class":131},[110,2244,284],{"class":131},[110,2246,288],{"class":287},[110,2248,281],{"class":131},[110,2250,293],{"class":287},[110,2252,220],{"class":131},[110,2254,298],{"class":192},[110,2256,301],{"class":131},[110,2258,2259,2261,2263,2265,2267,2269,2272,2274,2277,2279,2281,2283,2285,2287,2290,2292,2295,2297,2299],{"class":112,"line":818},[110,2260,306],{"class":208},[110,2262,266],{"class":131},[110,2264,443],{"class":204},[110,2266,209],{"class":314},[110,2268,1255],{"class":131},[110,2270,2271],{"class":314}," users",[110,2273,465],{"class":131},[110,2275,2276],{"class":314}," [",[110,2278,213],{"class":212},[110,2280,1275],{"class":127},[110,2282,213],{"class":212},[110,2284,281],{"class":131},[110,2286,483],{"class":212},[110,2288,2289],{"class":127},"Bob",[110,2291,213],{"class":212},[110,2293,2294],{"class":314},"] ",[110,2296,331],{"class":131},[110,2298,220],{"class":314},[110,2300,223],{"class":131},[110,2302,2303,2305,2307],{"class":112,"line":853},[110,2304,331],{"class":131},[110,2306,220],{"class":208},[110,2308,223],{"class":131},[110,2310,2311],{"class":112,"line":880},[110,2312,159],{"emptyLinePlaceholder":158},[110,2314,2315,2317,2319,2321,2323,2325,2327,2329,2331,2333,2335,2337,2339,2341,2343],{"class":112,"line":889},[110,2316,2137],{"class":208},[110,2318,266],{"class":131},[110,2320,269],{"class":204},[110,2322,209],{"class":208},[110,2324,213],{"class":212},[110,2326,558],{"class":127},[110,2328,213],{"class":212},[110,2330,281],{"class":131},[110,2332,284],{"class":131},[110,2334,288],{"class":287},[110,2336,281],{"class":131},[110,2338,293],{"class":287},[110,2340,220],{"class":131},[110,2342,298],{"class":192},[110,2344,301],{"class":131},[110,2346,2347,2349,2351,2353,2355,2357,2360,2362,2365,2367,2369,2371,2373,2375,2377],{"class":112,"line":894},[110,2348,306],{"class":208},[110,2350,266],{"class":131},[110,2352,443],{"class":204},[110,2354,209],{"class":314},[110,2356,1255],{"class":131},[110,2358,2359],{"class":314}," userId",[110,2361,465],{"class":131},[110,2363,2364],{"class":208}," req",[110,2366,266],{"class":131},[110,2368,713],{"class":208},[110,2370,266],{"class":131},[110,2372,718],{"class":208},[110,2374,1280],{"class":131},[110,2376,220],{"class":314},[110,2378,223],{"class":131},[110,2380,2381,2383,2385],{"class":112,"line":900},[110,2382,331],{"class":131},[110,2384,220],{"class":208},[110,2386,223],{"class":131},[110,2388,2389],{"class":112,"line":934},[110,2390,159],{"emptyLinePlaceholder":158},[110,2392,2393,2395,2397,2399,2401,2403,2405,2407,2409,2411,2413,2415,2417,2419,2421],{"class":112,"line":967},[110,2394,2137],{"class":208},[110,2396,266],{"class":131},[110,2398,825],{"class":204},[110,2400,209],{"class":208},[110,2402,213],{"class":212},[110,2404,276],{"class":127},[110,2406,213],{"class":212},[110,2408,281],{"class":131},[110,2410,284],{"class":131},[110,2412,288],{"class":287},[110,2414,281],{"class":131},[110,2416,293],{"class":287},[110,2418,220],{"class":131},[110,2420,298],{"class":192},[110,2422,301],{"class":131},[110,2424,2425,2427,2429,2431,2433,2435,2437,2439,2441,2443,2445,2447,2449,2451,2453,2455,2457,2459],{"class":112,"line":1777},[110,2426,306],{"class":208},[110,2428,266],{"class":131},[110,2430,1342],{"class":204},[110,2432,209],{"class":314},[110,2434,1347],{"class":251},[110,2436,220],{"class":314},[110,2438,266],{"class":131},[110,2440,443],{"class":204},[110,2442,209],{"class":314},[110,2444,1255],{"class":131},[110,2446,1360],{"class":314},[110,2448,465],{"class":131},[110,2450,483],{"class":212},[110,2452,1367],{"class":127},[110,2454,213],{"class":212},[110,2456,1280],{"class":131},[110,2458,220],{"class":314},[110,2460,223],{"class":131},[110,2462,2463,2465,2467],{"class":112,"line":1782},[110,2464,331],{"class":131},[110,2466,220],{"class":208},[110,2468,223],{"class":131},[110,2470,2471],{"class":112,"line":1788},[110,2472,159],{"emptyLinePlaceholder":158},[110,2474,2475,2478,2480,2483,2485,2487],{"class":112,"line":1828},[110,2476,2477],{"class":455},"module",[110,2479,266],{"class":131},[110,2481,2482],{"class":455},"exports",[110,2484,201],{"class":200},[110,2486,2110],{"class":208},[110,2488,223],{"class":131},[100,2490,2492],{"className":183,"code":2491,"language":185,"meta":105,"style":105},"\u002F\u002F app.js 主文件\nconst express = require(\"express\");\nconst userRoutes = require(\".\u002Froutes\u002Fusers\");\n\nconst app = express();\napp.use(express.json());\n\n\u002F\u002F 挂载路由：所有以 \u002Fapi\u002Fusers 开头的请求都会进入 userRoutes\napp.use(\"\u002Fapi\u002Fusers\", userRoutes);\n\napp.listen(3000);\n",[107,2493,2494,2499,2521,2545,2549,2563,2583,2587,2592,2615,2619],{"__ignoreMap":105},[110,2495,2496],{"class":112,"line":113},[110,2497,2498],{"class":116},"\u002F\u002F app.js 主文件\n",[110,2500,2501,2503,2505,2507,2509,2511,2513,2515,2517,2519],{"class":112,"line":120},[110,2502,193],{"class":192},[110,2504,197],{"class":196},[110,2506,201],{"class":200},[110,2508,205],{"class":204},[110,2510,209],{"class":208},[110,2512,213],{"class":212},[110,2514,12],{"class":127},[110,2516,213],{"class":212},[110,2518,220],{"class":208},[110,2520,223],{"class":131},[110,2522,2523,2525,2528,2530,2532,2534,2536,2539,2541,2543],{"class":112,"line":142},[110,2524,193],{"class":192},[110,2526,2527],{"class":196}," userRoutes",[110,2529,201],{"class":200},[110,2531,205],{"class":204},[110,2533,209],{"class":208},[110,2535,213],{"class":212},[110,2537,2538],{"class":127},".\u002Froutes\u002Fusers",[110,2540,213],{"class":212},[110,2542,220],{"class":208},[110,2544,223],{"class":131},[110,2546,2547],{"class":112,"line":155},[110,2548,159],{"emptyLinePlaceholder":158},[110,2550,2551,2553,2555,2557,2559,2561],{"class":112,"line":162},[110,2552,193],{"class":192},[110,2554,230],{"class":196},[110,2556,201],{"class":200},[110,2558,197],{"class":204},[110,2560,237],{"class":208},[110,2562,223],{"class":131},[110,2564,2565,2567,2569,2571,2574,2576,2578,2581],{"class":112,"line":168},[110,2566,263],{"class":208},[110,2568,266],{"class":131},[110,2570,2142],{"class":204},[110,2572,2573],{"class":208},"(express",[110,2575,266],{"class":131},[110,2577,443],{"class":204},[110,2579,2580],{"class":208},"())",[110,2582,223],{"class":131},[110,2584,2585],{"class":112,"line":328},[110,2586,159],{"emptyLinePlaceholder":158},[110,2588,2589],{"class":112,"line":338},[110,2590,2591],{"class":116},"\u002F\u002F 挂载路由：所有以 \u002Fapi\u002Fusers 开头的请求都会进入 userRoutes\n",[110,2593,2594,2596,2598,2600,2602,2604,2606,2608,2610,2613],{"class":112,"line":343},[110,2595,263],{"class":208},[110,2597,266],{"class":131},[110,2599,2142],{"class":204},[110,2601,209],{"class":208},[110,2603,213],{"class":212},[110,2605,650],{"class":127},[110,2607,213],{"class":212},[110,2609,281],{"class":131},[110,2611,2612],{"class":208}," userRoutes)",[110,2614,223],{"class":131},[110,2616,2617],{"class":112,"line":365},[110,2618,159],{"emptyLinePlaceholder":158},[110,2620,2621,2623,2625,2627,2629,2632,2634],{"class":112,"line":397},[110,2622,263],{"class":208},[110,2624,266],{"class":131},[110,2626,350],{"class":204},[110,2628,209],{"class":208},[110,2630,2631],{"class":251},"3000",[110,2633,220],{"class":208},[110,2635,223],{"class":131},[47,2637,2639],{"id":2638},"六中间件middleware","六、中间件（Middleware）",[22,2641,2642,2643,40,2645,2647,2648,2651],{},"中间件是 Express 的核心理念。一个中间件函数可以访问 ",[107,2644,288],{},[107,2646,1002],{}," 和 ",[107,2649,2650],{},"next","，它可以在请求到达最终处理函数之前\u002F之后执行各类逻辑，如日志记录、身份验证、请求解析等。",[95,2653,2655],{"id":2654},"_1-中间件的执行流程","1. 中间件的执行流程",[100,2657,2659],{"className":183,"code":2658,"language":185,"meta":105,"style":105},"const express = require(\"express\");\nconst app = express();\n\n\u002F\u002F 中间件1：记录日志\napp.use((req, res, next) => {\n  console.log(`${req.method} ${req.url} - ${new Date().toISOString()}`);\n  next(); \u002F\u002F 调用 next() 将控制权交给下一个中间件\n});\n\n\u002F\u002F 中间件2：添加自定义属性\napp.use((req, res, next) => {\n  req.requestTime = Date.now();\n  next();\n});\n\n\u002F\u002F 路由处理函数\napp.get(\"\u002F\", (req, res) => {\n  res.send(`请求时间: ${req.requestTime}`);\n});\n\napp.listen(3000);\n",[107,2660,2661,2683,2697,2701,2706,2734,2793,2805,2813,2817,2822,2850,2873,2881,2889,2893,2898,2930,2959,2967,2971],{"__ignoreMap":105},[110,2662,2663,2665,2667,2669,2671,2673,2675,2677,2679,2681],{"class":112,"line":113},[110,2664,193],{"class":192},[110,2666,197],{"class":196},[110,2668,201],{"class":200},[110,2670,205],{"class":204},[110,2672,209],{"class":208},[110,2674,213],{"class":212},[110,2676,12],{"class":127},[110,2678,213],{"class":212},[110,2680,220],{"class":208},[110,2682,223],{"class":131},[110,2684,2685,2687,2689,2691,2693,2695],{"class":112,"line":120},[110,2686,193],{"class":192},[110,2688,230],{"class":196},[110,2690,201],{"class":200},[110,2692,197],{"class":204},[110,2694,237],{"class":208},[110,2696,223],{"class":131},[110,2698,2699],{"class":112,"line":142},[110,2700,159],{"emptyLinePlaceholder":158},[110,2702,2703],{"class":112,"line":155},[110,2704,2705],{"class":116},"\u002F\u002F 中间件1：记录日志\n",[110,2707,2708,2710,2712,2714,2716,2718,2720,2722,2724,2726,2728,2730,2732],{"class":112,"line":162},[110,2709,263],{"class":208},[110,2711,266],{"class":131},[110,2713,2142],{"class":204},[110,2715,209],{"class":208},[110,2717,209],{"class":131},[110,2719,288],{"class":287},[110,2721,281],{"class":131},[110,2723,293],{"class":287},[110,2725,281],{"class":131},[110,2727,1819],{"class":287},[110,2729,220],{"class":131},[110,2731,298],{"class":192},[110,2733,301],{"class":131},[110,2735,2736,2738,2740,2742,2744,2747,2749,2751,2753,2755,2757,2759,2761,2764,2766,2769,2771,2774,2777,2780,2782,2785,2787,2789,2791],{"class":112,"line":168},[110,2737,368],{"class":208},[110,2739,266],{"class":131},[110,2741,373],{"class":204},[110,2743,209],{"class":314},[110,2745,2746],{"class":212},"`${",[110,2748,288],{"class":208},[110,2750,266],{"class":212},[110,2752,2186],{"class":208},[110,2754,331],{"class":212},[110,2756,2191],{"class":212},[110,2758,288],{"class":208},[110,2760,266],{"class":212},[110,2762,2763],{"class":208},"url",[110,2765,331],{"class":212},[110,2767,2768],{"class":127}," - ",[110,2770,384],{"class":212},[110,2772,2773],{"class":200},"new",[110,2775,2776],{"class":204}," Date",[110,2778,237],{"class":2779},"sfo-9",[110,2781,266],{"class":212},[110,2783,2784],{"class":204},"toISOString",[110,2786,237],{"class":2779},[110,2788,390],{"class":212},[110,2790,220],{"class":314},[110,2792,223],{"class":131},[110,2794,2795,2797,2799,2802],{"class":112,"line":328},[110,2796,1853],{"class":204},[110,2798,237],{"class":314},[110,2800,2801],{"class":131},";",[110,2803,2804],{"class":116}," \u002F\u002F 调用 next() 将控制权交给下一个中间件\n",[110,2806,2807,2809,2811],{"class":112,"line":338},[110,2808,331],{"class":131},[110,2810,220],{"class":208},[110,2812,223],{"class":131},[110,2814,2815],{"class":112,"line":343},[110,2816,159],{"emptyLinePlaceholder":158},[110,2818,2819],{"class":112,"line":365},[110,2820,2821],{"class":116},"\u002F\u002F 中间件2：添加自定义属性\n",[110,2823,2824,2826,2828,2830,2832,2834,2836,2838,2840,2842,2844,2846,2848],{"class":112,"line":397},[110,2825,263],{"class":208},[110,2827,266],{"class":131},[110,2829,2142],{"class":204},[110,2831,209],{"class":208},[110,2833,209],{"class":131},[110,2835,288],{"class":287},[110,2837,281],{"class":131},[110,2839,293],{"class":287},[110,2841,281],{"class":131},[110,2843,1819],{"class":287},[110,2845,220],{"class":131},[110,2847,298],{"class":192},[110,2849,301],{"class":131},[110,2851,2852,2855,2857,2860,2862,2864,2866,2869,2871],{"class":112,"line":818},[110,2853,2854],{"class":208},"  req",[110,2856,266],{"class":131},[110,2858,2859],{"class":208},"requestTime",[110,2861,201],{"class":200},[110,2863,2776],{"class":208},[110,2865,266],{"class":131},[110,2867,2868],{"class":204},"now",[110,2870,237],{"class":314},[110,2872,223],{"class":131},[110,2874,2875,2877,2879],{"class":112,"line":853},[110,2876,1853],{"class":204},[110,2878,237],{"class":314},[110,2880,223],{"class":131},[110,2882,2883,2885,2887],{"class":112,"line":880},[110,2884,331],{"class":131},[110,2886,220],{"class":208},[110,2888,223],{"class":131},[110,2890,2891],{"class":112,"line":889},[110,2892,159],{"emptyLinePlaceholder":158},[110,2894,2895],{"class":112,"line":894},[110,2896,2897],{"class":116},"\u002F\u002F 路由处理函数\n",[110,2899,2900,2902,2904,2906,2908,2910,2912,2914,2916,2918,2920,2922,2924,2926,2928],{"class":112,"line":900},[110,2901,263],{"class":208},[110,2903,266],{"class":131},[110,2905,269],{"class":204},[110,2907,209],{"class":208},[110,2909,213],{"class":212},[110,2911,276],{"class":127},[110,2913,213],{"class":212},[110,2915,281],{"class":131},[110,2917,284],{"class":131},[110,2919,288],{"class":287},[110,2921,281],{"class":131},[110,2923,293],{"class":287},[110,2925,220],{"class":131},[110,2927,298],{"class":192},[110,2929,301],{"class":131},[110,2931,2932,2934,2936,2938,2940,2942,2945,2947,2949,2951,2953,2955,2957],{"class":112,"line":934},[110,2933,306],{"class":208},[110,2935,266],{"class":131},[110,2937,311],{"class":204},[110,2939,209],{"class":314},[110,2941,378],{"class":212},[110,2943,2944],{"class":127},"请求时间: ",[110,2946,384],{"class":212},[110,2948,288],{"class":208},[110,2950,266],{"class":212},[110,2952,2859],{"class":208},[110,2954,390],{"class":212},[110,2956,220],{"class":314},[110,2958,223],{"class":131},[110,2960,2961,2963,2965],{"class":112,"line":967},[110,2962,331],{"class":131},[110,2964,220],{"class":208},[110,2966,223],{"class":131},[110,2968,2969],{"class":112,"line":1777},[110,2970,159],{"emptyLinePlaceholder":158},[110,2972,2973,2975,2977,2979,2981,2983,2985],{"class":112,"line":1782},[110,2974,263],{"class":208},[110,2976,266],{"class":131},[110,2978,350],{"class":204},[110,2980,209],{"class":208},[110,2982,2631],{"class":251},[110,2984,220],{"class":208},[110,2986,223],{"class":131},[95,2988,2990],{"id":2989},"_2-中间件的常见类型","2. 中间件的常见类型",[52,2992,2993,3009,3019,3032],{},[55,2994,2995,2998,2999,40,3002,3005,3006,3008],{},[32,2996,2997],{},"应用级中间件","：通过 ",[107,3000,3001],{},"app.use()",[107,3003,3004],{},"app.METHOD()"," 绑定到 ",[107,3007,263],{}," 对象",[55,3010,3011,3014,3015,3018],{},[32,3012,3013],{},"路由级中间件","：绑定到 ",[107,3016,3017],{},"express.Router()"," 实例，语法与应用级中间件相同",[55,3020,3021,3024,3025,40,3027,40,3029],{},[32,3022,3023],{},"内置中间件","：Express 自带的中间件，如 ",[107,3026,988],{},[107,3028,992],{},[107,3030,3031],{},"express.static()",[55,3033,3034,3037,3038,40,3041,40,3044],{},[32,3035,3036],{},"第三方中间件","：通过 npm 安装的中间件，如 ",[107,3039,3040],{},"cors",[107,3042,3043],{},"helmet",[107,3045,3046],{},"morgan",[22,3048,3049],{},"各类型中间件的详细使用方式：",[100,3051,3053],{"className":183,"code":3052,"language":185,"meta":105,"style":105},"\u002F\u002F 应用级中间件（全局生效）\napp.use((req, res, next) => {\n  console.log(\"所有请求都会经过这里\");\n  next();\n});\n\n\u002F\u002F 路由级中间件（仅对该路径生效）\napp.use(\"\u002Fapi\u002Fprotected\", (req, res, next) => {\n  const token = req.headers.authorization;\n  if (!token) {\n    return res.status(401).json({ error: \"未授权\" });\n  }\n  next();\n});\n\n\u002F\u002F 内置中间件：解析 JSON 请求体\napp.use(express.json());\n\n\u002F\u002F 内置中间件：解析 URL-encoded 表单数据\napp.use(express.urlencoded({ extended: true }));\n\n\u002F\u002F 内置中间件：托管静态文件\napp.use(express.static(\"public\"));\n\n\u002F\u002F 第三方中间件示例：CORS\nconst cors = require(\"cors\");\napp.use(cors());\n\n\u002F\u002F 第三方中间件示例：安全头\nconst helmet = require(\"helmet\");\napp.use(helmet());\n\n\u002F\u002F 第三方中间件示例：Morgan 日志\nconst morgan = require(\"morgan\");\napp.use(morgan(\"dev\"));\n",[107,3054,3055,3060,3088,3109,3117,3125,3129,3134,3171,3194,3213,3257,3261,3269,3277,3281,3286,3304,3308,3313,3348,3352,3357,3385,3389,3394,3418,3435,3440,3446,3470,3487,3492,3498,3522],{"__ignoreMap":105},[110,3056,3057],{"class":112,"line":113},[110,3058,3059],{"class":116},"\u002F\u002F 应用级中间件（全局生效）\n",[110,3061,3062,3064,3066,3068,3070,3072,3074,3076,3078,3080,3082,3084,3086],{"class":112,"line":120},[110,3063,263],{"class":208},[110,3065,266],{"class":131},[110,3067,2142],{"class":204},[110,3069,209],{"class":208},[110,3071,209],{"class":131},[110,3073,288],{"class":287},[110,3075,281],{"class":131},[110,3077,293],{"class":287},[110,3079,281],{"class":131},[110,3081,1819],{"class":287},[110,3083,220],{"class":131},[110,3085,298],{"class":192},[110,3087,301],{"class":131},[110,3089,3090,3092,3094,3096,3098,3100,3103,3105,3107],{"class":112,"line":142},[110,3091,368],{"class":208},[110,3093,266],{"class":131},[110,3095,373],{"class":204},[110,3097,209],{"class":314},[110,3099,213],{"class":212},[110,3101,3102],{"class":127},"所有请求都会经过这里",[110,3104,213],{"class":212},[110,3106,220],{"class":314},[110,3108,223],{"class":131},[110,3110,3111,3113,3115],{"class":112,"line":155},[110,3112,1853],{"class":204},[110,3114,237],{"class":314},[110,3116,223],{"class":131},[110,3118,3119,3121,3123],{"class":112,"line":162},[110,3120,331],{"class":131},[110,3122,220],{"class":208},[110,3124,223],{"class":131},[110,3126,3127],{"class":112,"line":168},[110,3128,159],{"emptyLinePlaceholder":158},[110,3130,3131],{"class":112,"line":328},[110,3132,3133],{"class":116},"\u002F\u002F 路由级中间件（仅对该路径生效）\n",[110,3135,3136,3138,3140,3142,3144,3146,3149,3151,3153,3155,3157,3159,3161,3163,3165,3167,3169],{"class":112,"line":338},[110,3137,263],{"class":208},[110,3139,266],{"class":131},[110,3141,2142],{"class":204},[110,3143,209],{"class":208},[110,3145,213],{"class":212},[110,3147,3148],{"class":127},"\u002Fapi\u002Fprotected",[110,3150,213],{"class":212},[110,3152,281],{"class":131},[110,3154,284],{"class":131},[110,3156,288],{"class":287},[110,3158,281],{"class":131},[110,3160,293],{"class":287},[110,3162,281],{"class":131},[110,3164,1819],{"class":287},[110,3166,220],{"class":131},[110,3168,298],{"class":192},[110,3170,301],{"class":131},[110,3172,3173,3176,3179,3181,3183,3185,3187,3189,3192],{"class":112,"line":343},[110,3174,3175],{"class":192},"  const",[110,3177,3178],{"class":196}," token",[110,3180,201],{"class":200},[110,3182,2364],{"class":208},[110,3184,266],{"class":131},[110,3186,949],{"class":208},[110,3188,266],{"class":131},[110,3190,3191],{"class":208},"authorization",[110,3193,223],{"class":131},[110,3195,3196,3200,3202,3205,3208,3211],{"class":112,"line":365},[110,3197,3199],{"class":3198},"sVHd0","  if",[110,3201,284],{"class":314},[110,3203,3204],{"class":200},"!",[110,3206,3207],{"class":208},"token",[110,3209,3210],{"class":314},") ",[110,3212,450],{"class":131},[110,3214,3215,3218,3220,3222,3224,3226,3229,3231,3233,3235,3237,3239,3242,3244,3246,3249,3251,3253,3255],{"class":112,"line":397},[110,3216,3217],{"class":3198},"    return",[110,3219,293],{"class":208},[110,3221,266],{"class":131},[110,3223,1342],{"class":204},[110,3225,209],{"class":314},[110,3227,3228],{"class":251},"401",[110,3230,220],{"class":314},[110,3232,266],{"class":131},[110,3234,443],{"class":204},[110,3236,209],{"class":314},[110,3238,1255],{"class":131},[110,3240,3241],{"class":314}," error",[110,3243,465],{"class":131},[110,3245,483],{"class":212},[110,3247,3248],{"class":127},"未授权",[110,3250,213],{"class":212},[110,3252,1280],{"class":131},[110,3254,220],{"class":314},[110,3256,223],{"class":131},[110,3258,3259],{"class":112,"line":818},[110,3260,494],{"class":131},[110,3262,3263,3265,3267],{"class":112,"line":853},[110,3264,1853],{"class":204},[110,3266,237],{"class":314},[110,3268,223],{"class":131},[110,3270,3271,3273,3275],{"class":112,"line":880},[110,3272,331],{"class":131},[110,3274,220],{"class":208},[110,3276,223],{"class":131},[110,3278,3279],{"class":112,"line":889},[110,3280,159],{"emptyLinePlaceholder":158},[110,3282,3283],{"class":112,"line":894},[110,3284,3285],{"class":116},"\u002F\u002F 内置中间件：解析 JSON 请求体\n",[110,3287,3288,3290,3292,3294,3296,3298,3300,3302],{"class":112,"line":900},[110,3289,263],{"class":208},[110,3291,266],{"class":131},[110,3293,2142],{"class":204},[110,3295,2573],{"class":208},[110,3297,266],{"class":131},[110,3299,443],{"class":204},[110,3301,2580],{"class":208},[110,3303,223],{"class":131},[110,3305,3306],{"class":112,"line":934},[110,3307,159],{"emptyLinePlaceholder":158},[110,3309,3310],{"class":112,"line":967},[110,3311,3312],{"class":116},"\u002F\u002F 内置中间件：解析 URL-encoded 表单数据\n",[110,3314,3315,3317,3319,3321,3323,3325,3328,3330,3332,3335,3337,3341,3343,3346],{"class":112,"line":1777},[110,3316,263],{"class":208},[110,3318,266],{"class":131},[110,3320,2142],{"class":204},[110,3322,2573],{"class":208},[110,3324,266],{"class":131},[110,3326,3327],{"class":204},"urlencoded",[110,3329,209],{"class":208},[110,3331,1255],{"class":131},[110,3333,3334],{"class":314}," extended",[110,3336,465],{"class":131},[110,3338,3340],{"class":3339},"syTEX"," true",[110,3342,1280],{"class":131},[110,3344,3345],{"class":208},"))",[110,3347,223],{"class":131},[110,3349,3350],{"class":112,"line":1782},[110,3351,159],{"emptyLinePlaceholder":158},[110,3353,3354],{"class":112,"line":1788},[110,3355,3356],{"class":116},"\u002F\u002F 内置中间件：托管静态文件\n",[110,3358,3359,3361,3363,3365,3367,3369,3372,3374,3376,3379,3381,3383],{"class":112,"line":1828},[110,3360,263],{"class":208},[110,3362,266],{"class":131},[110,3364,2142],{"class":204},[110,3366,2573],{"class":208},[110,3368,266],{"class":131},[110,3370,3371],{"class":204},"static",[110,3373,209],{"class":208},[110,3375,213],{"class":212},[110,3377,3378],{"class":127},"public",[110,3380,213],{"class":212},[110,3382,3345],{"class":208},[110,3384,223],{"class":131},[110,3386,3387],{"class":112,"line":1850},[110,3388,159],{"emptyLinePlaceholder":158},[110,3390,3391],{"class":112,"line":1860},[110,3392,3393],{"class":116},"\u002F\u002F 第三方中间件示例：CORS\n",[110,3395,3397,3399,3402,3404,3406,3408,3410,3412,3414,3416],{"class":112,"line":3396},26,[110,3398,193],{"class":192},[110,3400,3401],{"class":196}," cors",[110,3403,201],{"class":200},[110,3405,205],{"class":204},[110,3407,209],{"class":208},[110,3409,213],{"class":212},[110,3411,3040],{"class":127},[110,3413,213],{"class":212},[110,3415,220],{"class":208},[110,3417,223],{"class":131},[110,3419,3421,3423,3425,3427,3429,3431,3433],{"class":112,"line":3420},27,[110,3422,263],{"class":208},[110,3424,266],{"class":131},[110,3426,2142],{"class":204},[110,3428,209],{"class":208},[110,3430,3040],{"class":204},[110,3432,2580],{"class":208},[110,3434,223],{"class":131},[110,3436,3438],{"class":112,"line":3437},28,[110,3439,159],{"emptyLinePlaceholder":158},[110,3441,3443],{"class":112,"line":3442},29,[110,3444,3445],{"class":116},"\u002F\u002F 第三方中间件示例：安全头\n",[110,3447,3449,3451,3454,3456,3458,3460,3462,3464,3466,3468],{"class":112,"line":3448},30,[110,3450,193],{"class":192},[110,3452,3453],{"class":196}," helmet",[110,3455,201],{"class":200},[110,3457,205],{"class":204},[110,3459,209],{"class":208},[110,3461,213],{"class":212},[110,3463,3043],{"class":127},[110,3465,213],{"class":212},[110,3467,220],{"class":208},[110,3469,223],{"class":131},[110,3471,3473,3475,3477,3479,3481,3483,3485],{"class":112,"line":3472},31,[110,3474,263],{"class":208},[110,3476,266],{"class":131},[110,3478,2142],{"class":204},[110,3480,209],{"class":208},[110,3482,3043],{"class":204},[110,3484,2580],{"class":208},[110,3486,223],{"class":131},[110,3488,3490],{"class":112,"line":3489},32,[110,3491,159],{"emptyLinePlaceholder":158},[110,3493,3495],{"class":112,"line":3494},33,[110,3496,3497],{"class":116},"\u002F\u002F 第三方中间件示例：Morgan 日志\n",[110,3499,3501,3503,3506,3508,3510,3512,3514,3516,3518,3520],{"class":112,"line":3500},34,[110,3502,193],{"class":192},[110,3504,3505],{"class":196}," morgan",[110,3507,201],{"class":200},[110,3509,205],{"class":204},[110,3511,209],{"class":208},[110,3513,213],{"class":212},[110,3515,3046],{"class":127},[110,3517,213],{"class":212},[110,3519,220],{"class":208},[110,3521,223],{"class":131},[110,3523,3525,3527,3529,3531,3533,3535,3537,3539,3541,3543,3545],{"class":112,"line":3524},35,[110,3526,263],{"class":208},[110,3528,266],{"class":131},[110,3530,2142],{"class":204},[110,3532,209],{"class":208},[110,3534,3046],{"class":204},[110,3536,209],{"class":208},[110,3538,213],{"class":212},[110,3540,476],{"class":127},[110,3542,213],{"class":212},[110,3544,3345],{"class":208},[110,3546,223],{"class":131},[95,3548,3550],{"id":3549},"_3-中间件的执行顺序","3. 中间件的执行顺序",[22,3552,3553],{},"中间件的加载顺序决定了执行的先后顺序。先加载的中间件先执行：",[100,3555,3557],{"className":183,"code":3556,"language":185,"meta":105,"style":105},"\u002F\u002F ❌ 错误顺序：路由在前，中间件在后\napp.get(\"\u002F\", (req, res) => res.send(\"Hello\"));\napp.use(logger); \u002F\u002F logger 永远不会执行\n\n\u002F\u002F ✅ 正确顺序：先加载全局中间件，后加载路由\napp.use(logger);\napp.get(\"\u002F\", (req, res) => res.send(\"Hello\"));\napp.use(notFoundHandler); \u002F\u002F 404 处理应放在最后\napp.use(errorHandler); \u002F\u002F 错误处理应放在最后\n",[107,3558,3559,3564,3613,3629,3633,3638,3650,3698,3714],{"__ignoreMap":105},[110,3560,3561],{"class":112,"line":113},[110,3562,3563],{"class":116},"\u002F\u002F ❌ 错误顺序：路由在前，中间件在后\n",[110,3565,3566,3568,3570,3572,3574,3576,3578,3580,3582,3584,3586,3588,3590,3592,3594,3596,3598,3600,3602,3604,3607,3609,3611],{"class":112,"line":120},[110,3567,263],{"class":208},[110,3569,266],{"class":131},[110,3571,269],{"class":204},[110,3573,209],{"class":208},[110,3575,213],{"class":212},[110,3577,276],{"class":127},[110,3579,213],{"class":212},[110,3581,281],{"class":131},[110,3583,284],{"class":131},[110,3585,288],{"class":287},[110,3587,281],{"class":131},[110,3589,293],{"class":287},[110,3591,220],{"class":131},[110,3593,298],{"class":192},[110,3595,293],{"class":208},[110,3597,266],{"class":131},[110,3599,311],{"class":204},[110,3601,209],{"class":208},[110,3603,213],{"class":212},[110,3605,3606],{"class":127},"Hello",[110,3608,213],{"class":212},[110,3610,3345],{"class":208},[110,3612,223],{"class":131},[110,3614,3615,3617,3619,3621,3624,3626],{"class":112,"line":142},[110,3616,263],{"class":208},[110,3618,266],{"class":131},[110,3620,2142],{"class":204},[110,3622,3623],{"class":208},"(logger)",[110,3625,2801],{"class":131},[110,3627,3628],{"class":116}," \u002F\u002F logger 永远不会执行\n",[110,3630,3631],{"class":112,"line":155},[110,3632,159],{"emptyLinePlaceholder":158},[110,3634,3635],{"class":112,"line":162},[110,3636,3637],{"class":116},"\u002F\u002F ✅ 正确顺序：先加载全局中间件，后加载路由\n",[110,3639,3640,3642,3644,3646,3648],{"class":112,"line":168},[110,3641,263],{"class":208},[110,3643,266],{"class":131},[110,3645,2142],{"class":204},[110,3647,3623],{"class":208},[110,3649,223],{"class":131},[110,3651,3652,3654,3656,3658,3660,3662,3664,3666,3668,3670,3672,3674,3676,3678,3680,3682,3684,3686,3688,3690,3692,3694,3696],{"class":112,"line":328},[110,3653,263],{"class":208},[110,3655,266],{"class":131},[110,3657,269],{"class":204},[110,3659,209],{"class":208},[110,3661,213],{"class":212},[110,3663,276],{"class":127},[110,3665,213],{"class":212},[110,3667,281],{"class":131},[110,3669,284],{"class":131},[110,3671,288],{"class":287},[110,3673,281],{"class":131},[110,3675,293],{"class":287},[110,3677,220],{"class":131},[110,3679,298],{"class":192},[110,3681,293],{"class":208},[110,3683,266],{"class":131},[110,3685,311],{"class":204},[110,3687,209],{"class":208},[110,3689,213],{"class":212},[110,3691,3606],{"class":127},[110,3693,213],{"class":212},[110,3695,3345],{"class":208},[110,3697,223],{"class":131},[110,3699,3700,3702,3704,3706,3709,3711],{"class":112,"line":338},[110,3701,263],{"class":208},[110,3703,266],{"class":131},[110,3705,2142],{"class":204},[110,3707,3708],{"class":208},"(notFoundHandler)",[110,3710,2801],{"class":131},[110,3712,3713],{"class":116}," \u002F\u002F 404 处理应放在最后\n",[110,3715,3716,3718,3720,3722,3725,3727],{"class":112,"line":343},[110,3717,263],{"class":208},[110,3719,266],{"class":131},[110,3721,2142],{"class":204},[110,3723,3724],{"class":208},"(errorHandler)",[110,3726,2801],{"class":131},[110,3728,3729],{"class":116}," \u002F\u002F 错误处理应放在最后\n",[975,3731,3732],{},[22,3733,3734,414,3737,3740,3741,3743,3744,3746],{},[32,3735,3736],{},"重要",[107,3738,3739],{},"next()"," 是中间件链的“通行证”。如果不调用 ",[107,3742,3739],{}," 且没有结束响应（如用 ",[107,3745,1025],{},"），请求将被挂起，直到超时。",[47,3748,3750],{"id":3749},"七错误处理","七、错误处理",[22,3752,3753,3754,414,3757,45],{},"Express 内置了一个默认的错误处理程序，同时支持自定义错误处理中间件。错误处理中间件与普通中间件的唯一区别是",[32,3755,3756],{},"四个参数",[107,3758,3759],{},"(err, req, res, next)",[95,3761,3763],{"id":3762},"_1-同步错误","1. 同步错误",[22,3765,3766],{},"Express 会自动捕获同步代码中抛出的错误：",[100,3768,3770],{"className":183,"code":3769,"language":185,"meta":105,"style":105},"app.get(\"\u002F\", (req, res) => {\n  throw new Error(\"出错了！\"); \u002F\u002F Express 会自动捕获\n});\n",[107,3771,3772,3804,3831],{"__ignoreMap":105},[110,3773,3774,3776,3778,3780,3782,3784,3786,3788,3790,3792,3794,3796,3798,3800,3802],{"class":112,"line":113},[110,3775,263],{"class":208},[110,3777,266],{"class":131},[110,3779,269],{"class":204},[110,3781,209],{"class":208},[110,3783,213],{"class":212},[110,3785,276],{"class":127},[110,3787,213],{"class":212},[110,3789,281],{"class":131},[110,3791,284],{"class":131},[110,3793,288],{"class":287},[110,3795,281],{"class":131},[110,3797,293],{"class":287},[110,3799,220],{"class":131},[110,3801,298],{"class":192},[110,3803,301],{"class":131},[110,3805,3806,3809,3812,3815,3817,3819,3822,3824,3826,3828],{"class":112,"line":120},[110,3807,3808],{"class":3198},"  throw",[110,3810,3811],{"class":200}," new",[110,3813,3814],{"class":204}," Error",[110,3816,209],{"class":314},[110,3818,213],{"class":212},[110,3820,3821],{"class":127},"出错了！",[110,3823,213],{"class":212},[110,3825,220],{"class":314},[110,3827,2801],{"class":131},[110,3829,3830],{"class":116}," \u002F\u002F Express 会自动捕获\n",[110,3832,3833,3835,3837],{"class":112,"line":142},[110,3834,331],{"class":131},[110,3836,220],{"class":208},[110,3838,223],{"class":131},[95,3840,3842],{"id":3841},"_2-异步错误","2. 异步错误",[22,3844,3845,3846,3848,3849,414],{},"异步错误必须通过 ",[107,3847,3739],{}," 传递给 Express。在 Express 5 中，返回 Promise 的异步函数若拒绝，会自动调用 ",[107,3850,2650],{},[100,3852,3854],{"className":183,"code":3853,"language":185,"meta":105,"style":105},"\u002F\u002F Express 4 及以下：需要手动传递\napp.get(\"\u002Ffile\", (req, res, next) => {\n  fs.readFile(\"\u002Fsome-file\", (err, data) => {\n    if (err) {\n      next(err); \u002F\u002F 将错误传递给 Express\n    } else {\n      res.send(data);\n    }\n  });\n});\n\n\u002F\u002F Express 5：自动处理 Promise\u002Fpromise reject\napp.get(\"\u002Fuser\u002F:id\", async (req, res, next) => {\n  const user = await getUserById(req.params.id);\n  res.send(user); \u002F\u002F 如果 getUserById 抛出异常，Express 会自动调用 next\n});\n",[107,3855,3856,3861,3898,3935,3948,3964,3974,3992,3997,4006,4014,4018,4023,4062,4093,4113],{"__ignoreMap":105},[110,3857,3858],{"class":112,"line":113},[110,3859,3860],{"class":116},"\u002F\u002F Express 4 及以下：需要手动传递\n",[110,3862,3863,3865,3867,3869,3871,3873,3876,3878,3880,3882,3884,3886,3888,3890,3892,3894,3896],{"class":112,"line":120},[110,3864,263],{"class":208},[110,3866,266],{"class":131},[110,3868,269],{"class":204},[110,3870,209],{"class":208},[110,3872,213],{"class":212},[110,3874,3875],{"class":127},"\u002Ffile",[110,3877,213],{"class":212},[110,3879,281],{"class":131},[110,3881,284],{"class":131},[110,3883,288],{"class":287},[110,3885,281],{"class":131},[110,3887,293],{"class":287},[110,3889,281],{"class":131},[110,3891,1819],{"class":287},[110,3893,220],{"class":131},[110,3895,298],{"class":192},[110,3897,301],{"class":131},[110,3899,3900,3903,3905,3908,3910,3912,3915,3917,3919,3921,3924,3926,3929,3931,3933],{"class":112,"line":142},[110,3901,3902],{"class":208},"  fs",[110,3904,266],{"class":131},[110,3906,3907],{"class":204},"readFile",[110,3909,209],{"class":314},[110,3911,213],{"class":212},[110,3913,3914],{"class":127},"\u002Fsome-file",[110,3916,213],{"class":212},[110,3918,281],{"class":131},[110,3920,284],{"class":131},[110,3922,3923],{"class":287},"err",[110,3925,281],{"class":131},[110,3927,3928],{"class":287}," data",[110,3930,220],{"class":131},[110,3932,298],{"class":192},[110,3934,301],{"class":131},[110,3936,3937,3940,3942,3944,3946],{"class":112,"line":155},[110,3938,3939],{"class":3198},"    if",[110,3941,284],{"class":314},[110,3943,3923],{"class":208},[110,3945,3210],{"class":314},[110,3947,450],{"class":131},[110,3949,3950,3953,3955,3957,3959,3961],{"class":112,"line":162},[110,3951,3952],{"class":204},"      next",[110,3954,209],{"class":314},[110,3956,3923],{"class":208},[110,3958,220],{"class":314},[110,3960,2801],{"class":131},[110,3962,3963],{"class":116}," \u002F\u002F 将错误传递给 Express\n",[110,3965,3966,3969,3972],{"class":112,"line":168},[110,3967,3968],{"class":131},"    }",[110,3970,3971],{"class":3198}," else",[110,3973,301],{"class":131},[110,3975,3976,3979,3981,3983,3985,3988,3990],{"class":112,"line":328},[110,3977,3978],{"class":208},"      res",[110,3980,266],{"class":131},[110,3982,311],{"class":204},[110,3984,209],{"class":314},[110,3986,3987],{"class":208},"data",[110,3989,220],{"class":314},[110,3991,223],{"class":131},[110,3993,3994],{"class":112,"line":338},[110,3995,3996],{"class":131},"    }\n",[110,3998,3999,4002,4004],{"class":112,"line":343},[110,4000,4001],{"class":131},"  }",[110,4003,220],{"class":314},[110,4005,223],{"class":131},[110,4007,4008,4010,4012],{"class":112,"line":365},[110,4009,331],{"class":131},[110,4011,220],{"class":208},[110,4013,223],{"class":131},[110,4015,4016],{"class":112,"line":397},[110,4017,159],{"emptyLinePlaceholder":158},[110,4019,4020],{"class":112,"line":818},[110,4021,4022],{"class":116},"\u002F\u002F Express 5：自动处理 Promise\u002Fpromise reject\n",[110,4024,4025,4027,4029,4031,4033,4035,4037,4039,4041,4044,4046,4048,4050,4052,4054,4056,4058,4060],{"class":112,"line":853},[110,4026,263],{"class":208},[110,4028,266],{"class":131},[110,4030,269],{"class":204},[110,4032,209],{"class":208},[110,4034,213],{"class":212},[110,4036,678],{"class":127},[110,4038,213],{"class":212},[110,4040,281],{"class":131},[110,4042,4043],{"class":192}," async",[110,4045,284],{"class":131},[110,4047,288],{"class":287},[110,4049,281],{"class":131},[110,4051,293],{"class":287},[110,4053,281],{"class":131},[110,4055,1819],{"class":287},[110,4057,220],{"class":131},[110,4059,298],{"class":192},[110,4061,301],{"class":131},[110,4063,4064,4066,4069,4071,4074,4077,4079,4081,4083,4085,4087,4089,4091],{"class":112,"line":880},[110,4065,3175],{"class":192},[110,4067,4068],{"class":196}," user",[110,4070,201],{"class":200},[110,4072,4073],{"class":3198}," await",[110,4075,4076],{"class":204}," getUserById",[110,4078,209],{"class":314},[110,4080,288],{"class":208},[110,4082,266],{"class":131},[110,4084,713],{"class":208},[110,4086,266],{"class":131},[110,4088,718],{"class":208},[110,4090,220],{"class":314},[110,4092,223],{"class":131},[110,4094,4095,4097,4099,4101,4103,4106,4108,4110],{"class":112,"line":889},[110,4096,306],{"class":208},[110,4098,266],{"class":131},[110,4100,311],{"class":204},[110,4102,209],{"class":314},[110,4104,4105],{"class":208},"user",[110,4107,220],{"class":314},[110,4109,2801],{"class":131},[110,4111,4112],{"class":116}," \u002F\u002F 如果 getUserById 抛出异常，Express 会自动调用 next\n",[110,4114,4115,4117,4119],{"class":112,"line":894},[110,4116,331],{"class":131},[110,4118,220],{"class":208},[110,4120,223],{"class":131},[95,4122,4124],{"id":4123},"_3-自定义错误处理中间件","3. 自定义错误处理中间件",[22,4126,4127,4128,4131],{},"必须定义在",[32,4129,4130],{},"所有路由之后","，并声明四个参数：",[100,4133,4135],{"className":183,"code":4134,"language":185,"meta":105,"style":105},"\u002F\u002F 普通路由\napp.get(\"\u002F\", (req, res) => {\n  res.send(\"Hello\");\n});\n\n\u002F\u002F 404 处理（没有匹配到任何路由时）\napp.use((req, res, next) => {\n  res.status(404).json({ error: \"请求的资源不存在\" });\n});\n\n\u002F\u002F 全局错误处理中间件（放在最后）\napp.use((err, req, res, next) => {\n  console.error(\"错误信息:\", err.stack);\n  res.status(500).json({ error: \"服务器内部错误\" });\n});\n",[107,4136,4137,4142,4174,4194,4202,4206,4211,4239,4279,4287,4291,4296,4328,4360,4400],{"__ignoreMap":105},[110,4138,4139],{"class":112,"line":113},[110,4140,4141],{"class":116},"\u002F\u002F 普通路由\n",[110,4143,4144,4146,4148,4150,4152,4154,4156,4158,4160,4162,4164,4166,4168,4170,4172],{"class":112,"line":120},[110,4145,263],{"class":208},[110,4147,266],{"class":131},[110,4149,269],{"class":204},[110,4151,209],{"class":208},[110,4153,213],{"class":212},[110,4155,276],{"class":127},[110,4157,213],{"class":212},[110,4159,281],{"class":131},[110,4161,284],{"class":131},[110,4163,288],{"class":287},[110,4165,281],{"class":131},[110,4167,293],{"class":287},[110,4169,220],{"class":131},[110,4171,298],{"class":192},[110,4173,301],{"class":131},[110,4175,4176,4178,4180,4182,4184,4186,4188,4190,4192],{"class":112,"line":142},[110,4177,306],{"class":208},[110,4179,266],{"class":131},[110,4181,311],{"class":204},[110,4183,209],{"class":314},[110,4185,213],{"class":212},[110,4187,3606],{"class":127},[110,4189,213],{"class":212},[110,4191,220],{"class":314},[110,4193,223],{"class":131},[110,4195,4196,4198,4200],{"class":112,"line":155},[110,4197,331],{"class":131},[110,4199,220],{"class":208},[110,4201,223],{"class":131},[110,4203,4204],{"class":112,"line":162},[110,4205,159],{"emptyLinePlaceholder":158},[110,4207,4208],{"class":112,"line":168},[110,4209,4210],{"class":116},"\u002F\u002F 404 处理（没有匹配到任何路由时）\n",[110,4212,4213,4215,4217,4219,4221,4223,4225,4227,4229,4231,4233,4235,4237],{"class":112,"line":328},[110,4214,263],{"class":208},[110,4216,266],{"class":131},[110,4218,2142],{"class":204},[110,4220,209],{"class":208},[110,4222,209],{"class":131},[110,4224,288],{"class":287},[110,4226,281],{"class":131},[110,4228,293],{"class":287},[110,4230,281],{"class":131},[110,4232,1819],{"class":287},[110,4234,220],{"class":131},[110,4236,298],{"class":192},[110,4238,301],{"class":131},[110,4240,4241,4243,4245,4247,4249,4252,4254,4256,4258,4260,4262,4264,4266,4268,4271,4273,4275,4277],{"class":112,"line":338},[110,4242,306],{"class":208},[110,4244,266],{"class":131},[110,4246,1342],{"class":204},[110,4248,209],{"class":314},[110,4250,4251],{"class":251},"404",[110,4253,220],{"class":314},[110,4255,266],{"class":131},[110,4257,443],{"class":204},[110,4259,209],{"class":314},[110,4261,1255],{"class":131},[110,4263,3241],{"class":314},[110,4265,465],{"class":131},[110,4267,483],{"class":212},[110,4269,4270],{"class":127},"请求的资源不存在",[110,4272,213],{"class":212},[110,4274,1280],{"class":131},[110,4276,220],{"class":314},[110,4278,223],{"class":131},[110,4280,4281,4283,4285],{"class":112,"line":343},[110,4282,331],{"class":131},[110,4284,220],{"class":208},[110,4286,223],{"class":131},[110,4288,4289],{"class":112,"line":365},[110,4290,159],{"emptyLinePlaceholder":158},[110,4292,4293],{"class":112,"line":397},[110,4294,4295],{"class":116},"\u002F\u002F 全局错误处理中间件（放在最后）\n",[110,4297,4298,4300,4302,4304,4306,4308,4310,4312,4314,4316,4318,4320,4322,4324,4326],{"class":112,"line":818},[110,4299,263],{"class":208},[110,4301,266],{"class":131},[110,4303,2142],{"class":204},[110,4305,209],{"class":208},[110,4307,209],{"class":131},[110,4309,3923],{"class":287},[110,4311,281],{"class":131},[110,4313,2364],{"class":287},[110,4315,281],{"class":131},[110,4317,293],{"class":287},[110,4319,281],{"class":131},[110,4321,1819],{"class":287},[110,4323,220],{"class":131},[110,4325,298],{"class":192},[110,4327,301],{"class":131},[110,4329,4330,4332,4334,4337,4339,4341,4344,4346,4348,4351,4353,4356,4358],{"class":112,"line":853},[110,4331,368],{"class":208},[110,4333,266],{"class":131},[110,4335,4336],{"class":204},"error",[110,4338,209],{"class":314},[110,4340,213],{"class":212},[110,4342,4343],{"class":127},"错误信息:",[110,4345,213],{"class":212},[110,4347,281],{"class":131},[110,4349,4350],{"class":208}," err",[110,4352,266],{"class":131},[110,4354,4355],{"class":208},"stack",[110,4357,220],{"class":314},[110,4359,223],{"class":131},[110,4361,4362,4364,4366,4368,4370,4373,4375,4377,4379,4381,4383,4385,4387,4389,4392,4394,4396,4398],{"class":112,"line":880},[110,4363,306],{"class":208},[110,4365,266],{"class":131},[110,4367,1342],{"class":204},[110,4369,209],{"class":314},[110,4371,4372],{"class":251},"500",[110,4374,220],{"class":314},[110,4376,266],{"class":131},[110,4378,443],{"class":204},[110,4380,209],{"class":314},[110,4382,1255],{"class":131},[110,4384,3241],{"class":314},[110,4386,465],{"class":131},[110,4388,483],{"class":212},[110,4390,4391],{"class":127},"服务器内部错误",[110,4393,213],{"class":212},[110,4395,1280],{"class":131},[110,4397,220],{"class":314},[110,4399,223],{"class":131},[110,4401,4402,4404,4406],{"class":112,"line":889},[110,4403,331],{"class":131},[110,4405,220],{"class":208},[110,4407,223],{"class":131},[47,4409,4411],{"id":4410},"八常用中间件速查表","八、常用中间件速查表",[518,4413,4414,4427],{},[521,4415,4416],{},[524,4417,4418,4421,4424],{},[527,4419,4420],{},"中间件",[527,4422,4423],{},"用途",[527,4425,4426],{},"安装命令",[537,4428,4429,4441,4452,4463,4477,4491,4505,4520,4535],{},[524,4430,4431,4435,4438],{},[542,4432,4433],{},[107,4434,988],{},[542,4436,4437],{},"解析 JSON 格式请求体",[542,4439,4440],{},"内置，无需安装",[524,4442,4443,4447,4450],{},[542,4444,4445],{},[107,4446,992],{},[542,4448,4449],{},"解析表单数据（URL-encoded）",[542,4451,4440],{},[524,4453,4454,4458,4461],{},[542,4455,4456],{},[107,4457,3031],{},[542,4459,4460],{},"托管静态文件",[542,4462,4440],{},[524,4464,4465,4469,4472],{},[542,4466,4467],{},[107,4468,3040],{},[542,4470,4471],{},"处理跨域资源共享",[542,4473,4474],{},[107,4475,4476],{},"npm install cors",[524,4478,4479,4483,4486],{},[542,4480,4481],{},[107,4482,3043],{},[542,4484,4485],{},"设置安全 HTTP 头，防御常见 Web 漏洞",[542,4487,4488],{},[107,4489,4490],{},"npm install helmet",[524,4492,4493,4497,4500],{},[542,4494,4495],{},[107,4496,3046],{},[542,4498,4499],{},"HTTP 请求日志记录",[542,4501,4502],{},[107,4503,4504],{},"npm install morgan",[524,4506,4507,4512,4515],{},[542,4508,4509],{},[107,4510,4511],{},"compression",[542,4513,4514],{},"Gzip 压缩响应内容",[542,4516,4517],{},[107,4518,4519],{},"npm install compression",[524,4521,4522,4527,4530],{},[542,4523,4524],{},[107,4525,4526],{},"express-rate-limit",[542,4528,4529],{},"限制重复请求频率（防暴力 \u002F DDoS）",[542,4531,4532],{},[107,4533,4534],{},"npm install express-rate-limit",[524,4536,4537,4542,4545],{},[542,4538,4539],{},[107,4540,4541],{},"cookie-parser",[542,4543,4544],{},"解析 Cookie",[542,4546,4547],{},[107,4548,4549],{},"npm install cookie-parser",[47,4551,4552],{"id":4552},"参考文献",[22,4554,4555],{},"以下链接在编写时均可正常访问：",[518,4557,4558,4567],{},[521,4559,4560],{},[524,4561,4562,4565],{},[527,4563,4564],{},"资料",[527,4566,532],{},[537,4568,4569,4581,4593],{},[524,4570,4571,4578],{},[542,4572,4573],{},[25,4574,4577],{"href":4575,"rel":4576},"https:\u002F\u002Fexpressjs.com\u002Fen\u002Fguide\u002Frouting.html",[29],"Express 指南",[542,4579,4580],{},"路由",[524,4582,4583,4590],{},[542,4584,4585],{},[25,4586,4589],{"href":4587,"rel":4588},"https:\u002F\u002Fexpressjs.com\u002Fen\u002Fguide\u002Fmigrating-5.html",[29],"Express 5 迁移",[542,4591,4592],{},"版本说明",[524,4594,4595,4602],{},[542,4596,4597],{},[25,4598,4601],{"href":4599,"rel":4600},"https:\u002F\u002Fnodejs.org\u002Fapi\u002Fhttp.html",[29],"Node.js http",[542,4603,4604],{},"底层模块",[4606,4607,4608],"style",{},"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 .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sptTA, html code.shiki .sptTA{--shiki-light:#6182B8;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .stzsN, html code.shiki .stzsN{--shiki-light:#91B859;--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 .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}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 .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}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 .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 pre.shiki code .sfo-9, html code.shiki .sfo-9{--shiki-light:#90A4AE;--shiki-default:#032F62;--shiki-dark:#9ECBFF}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 .syTEX, html code.shiki .syTEX{--shiki-light:#FF5370;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sseR_, html code.shiki .sseR_{--shiki-light:#9C3EDA;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZMiF, html code.shiki .sZMiF{--shiki-light:#E2931D;--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":105,"searchDepth":120,"depth":120,"links":4610},[4611,4612,4617,4618,4619,4625,4630,4635,4636],{"id":49,"depth":120,"text":50},{"id":92,"depth":120,"text":93,"children":4613},[4614,4615,4616],{"id":97,"depth":142,"text":98},{"id":179,"depth":142,"text":180},{"id":406,"depth":142,"text":407},{"id":509,"depth":120,"text":510},{"id":995,"depth":120,"text":996},{"id":1458,"depth":120,"text":1459,"children":4620},[4621,4622,4623],{"id":1465,"depth":142,"text":1466},{"id":1869,"depth":142,"text":1870},{"id":2060,"depth":142,"text":4624},"3. express.Router 模块化路由（推荐用于项目结构）",{"id":2638,"depth":120,"text":2639,"children":4626},[4627,4628,4629],{"id":2654,"depth":142,"text":2655},{"id":2989,"depth":142,"text":2990},{"id":3549,"depth":142,"text":3550},{"id":3749,"depth":120,"text":3750,"children":4631},[4632,4633,4634],{"id":3762,"depth":142,"text":3763},{"id":3841,"depth":142,"text":3842},{"id":4123,"depth":142,"text":4124},{"id":4410,"depth":120,"text":4411},{"id":4552,"depth":120,"text":4552},{"title":8,"description":9},"knowledge\u002Fbooklet\u002Fend\u002Fexpress","knowledge\u002Fknowledge\u002Fbooklet\u002Fend\u002Fexpress.md","md",{"items":4642},[4643,4645,4649,4653,4657,4661],{"path":38,"title":39,"description":4644,"category":10,"score":142},"本目录覆盖 JavaScript\u002FTypeScript 服务端运行时与框架、数据存储，以及 Rust 系统编程入门，提供从零到部署的完整学习路径。前置建议：JavaScript 基础、工程化 · 环境变量。",{"path":4646,"title":4647,"description":4648,"category":10,"score":142},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fbun\u002Fbase","Bun 基础与核心命令","Bun 是用 Zig 编写的 JavaScript 运行时，内置包管理（bun install）、打包（bun build）、测试（bun test）等，并持续兼容 Node.js API。本文介绍核心特点、安装方式，以及日常最常用的命令与包管理功能。见 运行时对比。",{"path":4650,"title":4651,"description":4652,"category":10,"score":142},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fbun\u002Fhttp","HTTP 服务器","Bun 内置了高性能的 HTTP 服务器，通过 Bun.serve 可以轻松启动服务。从 Bun v1.2.3 开始，推荐使用 routes 对象来定义路由，更加直观和灵活。",{"path":4654,"title":4655,"description":4656,"category":10,"score":142},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fcore\u002Ffs","文件系统","Node.js 的 fs 模块提供了与文件系统交互的 API，几乎涵盖了所有标准文件操作。它支持三种风格的 API：同步、回调式异步 和 Promise 式异步。下面详细介绍这些 API 的选择策略、流式读写、文件监视以及常用操作。",{"path":4658,"title":4659,"description":4660,"category":10,"score":142},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fdeno\u002Fbase","Deno 基础","Deno 是基于 V8 与 Rust 的 JavaScript\u002FTypeScript 运行时，由 Node.js 原作者 Ryan Dahl 发起。官方文档：docs.deno.com。与 Node、Bun 的对比见 运行时对比。",{"path":4662,"title":4663,"description":105,"category":10,"score":142},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fbefore\u002Fexce","异常处理器",{"series":4665,"title":4666,"items":4667,"index":3489,"prev":4922,"next":4923},"booklet\u002Fend","end",[4668,4672,4676,4680,4684,4688,4692,4694,4696,4697,4701,4705,4709,4713,4717,4721,4725,4729,4733,4737,4741,4745,4749,4753,4757,4759,4763,4767,4771,4775,4779,4783,4785,4786,4788,4792,4795,4799,4801,4805,4809,4813,4817,4821,4825,4829,4833,4837,4841,4845,4849,4853,4857,4861,4865,4868,4872,4876,4880,4884,4887,4891,4895,4899,4903,4907,4911,4914,4918],{"path":4669,"title":4670,"date":4671,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fasync","第九章：并发与异步","2020-05-22",{"path":4673,"title":4674,"date":4675,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fasync","异步编程与模式","2025-08-20",{"path":4677,"title":4678,"date":4679,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fdeno\u002Fauth","权限模型","2021-04-01",{"path":4681,"title":4682,"date":4683,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fauth","认证与授权","2025-12-23",{"path":4685,"title":4686,"date":4687,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fbase","Rust 基础","2020-07-21",{"path":4689,"title":4690,"date":4691,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fbase","NestJS 基础","2021-03-09",{"path":4658,"title":4659,"date":4693,"pinned":14},"2026-06-01",{"path":4646,"title":4647,"date":4695,"pinned":14},"2026-07-23",{"path":38,"title":39,"date":4695,"pinned":14},{"path":4698,"title":4699,"date":4700,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fcore\u002Fbuffer","缓冲区","2025-01-30",{"path":4702,"title":4703,"date":4704,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fbun-deno-node","Bun \u002F Deno \u002F Node 对比","2024-04-23",{"path":4706,"title":4707,"date":4708,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fcache","缓存","2025-07-04",{"path":4710,"title":4711,"date":4712,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fconfig","配置管理（Config 模块）","2023-08-26",{"path":4714,"title":4715,"date":4716,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fcontroller","控制器与路由","2020-07-18",{"path":4718,"title":4719,"date":4720,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fcore","第三章：所有权、借用与生命周期（核心）","2023-05-09",{"path":4722,"title":4723,"date":4724,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fcron","定时任务","2023-04-12",{"path":4726,"title":4727,"date":4728,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fcustom-decorators","自定义装饰器","2021-09-19",{"path":4730,"title":4731,"date":4732,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fdata-type","第四章：复合数据类型","2021-02-24",{"path":4734,"title":4735,"date":4736,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fdatabase","数据库集成（以 TypeORM 为例）","2023-05-26",{"path":4738,"title":4739,"date":4740,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fbefore\u002Fdatabase","数据库的配置","2024-06-22",{"path":4742,"title":4743,"date":4744,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fbefore\u002Fdemo","入手Demo","2022-10-15",{"path":4746,"title":4747,"date":4748,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fdeploy","部署与运维","2023-01-24",{"path":4750,"title":4751,"date":4752,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fbun\u002Fdeploy","生产环境与部署指南","2024-08-31",{"path":4754,"title":4755,"date":4756,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fdocs","第八章：测试、文档与质量","2026-01-11",{"path":43,"title":44,"date":4758,"pinned":14},"2019-11-03",{"path":4760,"title":4761,"date":4762,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fbefore\u002Fenv","环境加载","2024-09-01",{"path":4764,"title":4765,"date":4766,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Ferror","异常处理","2020-01-28",{"path":4768,"title":4769,"date":4770,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Ferror","错误处理与健壮性","2021-01-24",{"path":4772,"title":4773,"date":4774,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Ferror","第五章：错误处理","2023-11-03",{"path":4776,"title":4777,"date":4778,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fbase\u002Fevent","事件驱动与非阻塞 I\u002FO 模型","2020-06-20",{"path":4780,"title":4781,"date":4782,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fbase\u002Fevent-loop","事件循环","2024-11-20",{"path":4662,"title":4663,"date":4784,"pinned":14},"2026-03-17",{"path":7,"title":8,"date":13,"pinned":14},{"path":4654,"title":4655,"date":4787,"pinned":14},"2026-06-04",{"path":4789,"title":4790,"date":4791,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fguards","守卫 (Guards) 与授权","2023-09-09",{"path":4793,"title":4651,"date":4794,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fdeno\u002Fhttp","2020-12-11",{"path":4796,"title":4797,"date":4798,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fcore\u002Fhttp","网络编程","2023-01-27",{"path":4650,"title":4651,"date":4800,"pinned":14},"2026-07-12",{"path":4802,"title":4803,"date":4804,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fbefore\u002Finfo","归档说明（before\u002F）","2023-08-31",{"path":4806,"title":4807,"date":4808,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fdeno\u002Finit","项目初始化与基础命令","2025-02-14",{"path":4810,"title":4811,"date":4812,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fbefore\u002Finjectable","操作日志拦截器","2020-02-20",{"path":4814,"title":4815,"date":4816,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fdeno\u002Finstall","安装与环境","2021-02-05",{"path":4818,"title":4819,"date":4820,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fintercept","拦截器 (Interceptors)","2021-04-26",{"path":4822,"title":4823,"date":4824,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fbefore\u002Fitc","统一响应格式拦截器","2023-08-17",{"path":4826,"title":4827,"date":4828,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fbefore\u002Fjwt","JWT 与 Passport 授权","2021-08-10",{"path":4830,"title":4831,"date":4832,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Flogger","日志记录","2022-10-10",{"path":4834,"title":4835,"date":4836,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fbefore\u002Fmi","Nest 中间件","2022-06-21",{"path":4838,"title":4839,"date":4840,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fmiddleware","中间件 (Middleware)","2021-11-26",{"path":4842,"title":4843,"date":4844,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fbase\u002Fmodule","模块系统","2020-07-01",{"path":4846,"title":4847,"date":4848,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fmodule","模块系统与依赖注入","2022-06-15",{"path":4850,"title":4851,"date":4852,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs","NestJS 导读","2025-06-21",{"path":4854,"title":4855,"date":4856,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fbefore\u002Fnext","路由守卫","2022-12-01",{"path":4858,"title":4859,"date":4860,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fcore\u002Fother","其他常用模块","2020-03-27",{"path":4862,"title":4863,"date":4864,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fdeno\u002Fother","其他配置","2022-02-08",{"path":4866,"title":4863,"date":4867,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fbefore\u002Fother","2022-05-23",{"path":4869,"title":4870,"date":4871,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fother","第十章：进阶特性与模式","2023-12-29",{"path":4873,"title":4874,"date":4875,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fpackage","第七章：模块系统与包管理","2024-05-26",{"path":4877,"title":4878,"date":4879,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fdeno\u002Fpackage","包管理与依赖","2024-07-21",{"path":4881,"title":4882,"date":4883,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fcore\u002Fpath","路径处理","2024-03-14",{"path":4885,"title":4886,"date":4716,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fpipes","管道 (Pipes) 与数据验证",{"path":4888,"title":4889,"date":4890,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fcore\u002Fprocess","进程与子进程","2023-11-10",{"path":4892,"title":4893,"date":4894,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fqueue","队列（Bull）","2021-07-01",{"path":4896,"title":4897,"date":4898,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fservice","提供者与服务","2024-12-02",{"path":4900,"title":4901,"date":4902,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fcore\u002Fstream","流","2022-05-03",{"path":4904,"title":4905,"date":4906,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Ft","泛型与 Trait","2024-10-31",{"path":4908,"title":4909,"date":4910,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fdeno\u002Ftools","内置工具链","2026-01-24",{"path":4912,"title":4913,"date":4752,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Ftype","第二章：基础语法与类型",{"path":4915,"title":4916,"date":4917,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fbase\u002Fvar","全局对象与变量","2025-01-03",{"path":4919,"title":4920,"date":4921,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fwebsocket","WebSocket（网关）","2022-12-14",{"path":4662,"title":4663,"date":4784,"pinned":14},{"path":4654,"title":4655,"date":4787,"pinned":14}]