
freeCodeCamp 进阶 Node 与 Express 实战用 routes.js 与 auth.js 模块化重构单文件 server.js【免费下载链接】freeCodeCampfreeCodeCamp.orgs open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp在 freeCodeCamp 课程“Advanced Node and Express”中“Clean Up Your Project with Modules”这一练习要求学员把此前一路累积在server.js单文件里的全部路由与认证逻辑拆分为routes.js和auth.js两个模块并以module.exports function (app, myDataBase) {}工厂函数形式在数据库连接建立后注入。读完本文你将掌握这种“依赖注入式”模块拆分的具体步骤、各模块应迁移的代码清单、为什么实例化必须放在数据库连接回调之后以及课程测试是如何用正则校验server.js完成重构的。一、背景一个被逐章堆满的 server.js从课程块 advanced-node-and-express.json 的challengeOrder可以看到本练习id 为589690e6f9fc0f352b528e6e位于整个块的中间位置。在它之前学员已经在同一个server.js里依次写入了Pug 模板引擎的初始化与页面渲染Set up a Template Engine / Use a Template Engines Powersexpress-sessionpassport.initialize()/passport.session()的会话配置见 Set up Passportpassport.serializeUser/deserializeUser用户序列化以及用myDB(async client { ... }).catch(e {...})包裹路由、在数据库连接成功后才对外服务的结构见 Implement the Serialization of a Passport Userpassport.use(new LocalStrategy(...))本地认证策略内部依赖myDataBase.findOne见 Authentication Strategies/login、/profile、/logout、/register等路由见 How to Use Passport Strategies 与 Registration of New Usersbcrypt.hashSync/bcrypt.compareSync的密码哈希见 Hashing Your Passwords。到本练习开始时server.js同时承担“数据库连接管理、序列化、策略注册、业务路由”四种职责课程原文指出这正是问题所在“Right now, everything you have is in yourserver.jsfile. This can lead to hard to manage code that isnt very expandable.”现在你所有的东西都在server.js文件里这会导致难以管理、可扩展性差的代码。本练习的目标就是做第一次结构拆分为后续 Social Authentication 等章节继续扩张代码腾出空间。二、核心手法以 (app, myDataBase) 为参数的模块工厂函数课程要求新建的两个文件都以下列代码开头module.exports function (app, myDataBase) { }这是一种依赖注入式写法模块不自己require数据库连接、不自己持有app实例而是把 Express 应用和已就绪的 Mongo 集合作为参数“传进来”。由此带来两个好处模块内部所有需要myDataBase的逻辑序列化、LocalStrategy 的findOne、注册/登录路由都可以安全引用集合而不必关心连接何时建立调用顺序由server.js统一控制——模块只有在数据库连接成功后才被调用天然避免“连接未就绪就注册路由/策略”的时序错误。三、具体操作步骤原文给出的操作流程共四步这里结合前后章节的上下文完整还原。1. 创建 routes.js 与 auth.js在项目中创建两个新文件routes.js和auth.js内容都以第二节的工厂函数骨架开始。2. 在 server.js 顶部引入并在数据库连接成功后实例化在server.js文件顶部按如下方式引入这两个文件const routes require(./routes.js); const auth require(./auth.js);然后在“成功建立数据库连接之后”的位置即前文myDB(async client { ... })回调内部、拿到myDataBase之后分别实例化routes(app, myDataBase); auth(app, myDataBase);课程原文强调“Right after you establish a successful connection with the database”——实例化必须紧跟在数据库连接成功之后。原因在于 LocalStrategy 的findOne、deserializeUser的查询、/register的insertOne都直接操作myDataBase集合而myDataBase只有在myDB(async client {...})的回调参数里才存在参见 Implement the Serialization of a Passport User 中给出的const myDataBase await client.db(database).collection(users);。3. 迁移路由到 routes.jscatch 块路由除外把server.js中已有的全部路由首页GET /、POST /login、GET /profile、GET /logout、POST /register等剪切粘贴到routes.js并从server.js中删除。有一个明确例外catch 块中的那条路由必须留在server.js——即数据库连接失败时的兜底路由}).catch(e { app.route(/).get((req, res) { res.render(index, { title: e, message: Unable to connect to database }); }); });从源码结构看这条路由只依赖app不依赖myDataBase而且它本身是“连接失败”场景的组成部分因此留在server.js的.catch()链中语义最自然课程原文也特意加粗注明 “except for the route in the catch block”。同时ensureAuthenticated这个自写中间件要随路由一起搬进routes.js因为原文说明它 “was specifically created for routing”它就是为路由专门创建的。4. 在新文件中补齐依赖直到不再报错迁移之后routes.js里用到的每个符号都要在文件顶部、module.exports行之上重新声明依赖例如const passport require(passport); module.exports function (app, myDataBase) { // 从这里开始才是路由逻辑 }课程原话是“Keep adding them until no more errors exist, and your server file no longer has any routing (except for the route in the catch block)!”继续添加依赖直到不再有任何错误且 server 文件中除了 catch 块里的路由外不再有任何路由。四、auth.js 应迁移的内容auth.js的职责是“所有与认证相关的东西”原文要求“Do the same thing in yourauth.jsfile with all of the things related to authentication such as the serialization and the setting up of the local strategy and erase them from your server file. Be sure to add the dependencies in and callauth(app, myDataBase)in the server in the same spot.”在 auth.js 中对所有与认证相关的内容做同样的事比如序列化和 local 策略的设置并把这些从 server 文件中删掉记得把依赖加进去并在 server 文件的同一位置调用auth(app, myDataBase)。结合前序练习可以推断auth.js的迁移清单大致包括迁移项来源章节对 myDataBase 的依赖passport.serializeUser/deserializeUserSerialization of a User Object 系列练习deserializeUser内会用myDataBase.findOne查询用户文档passport.use(new LocalStrategy(...))Authentication Strategies策略内部执行myDataBase.findOne({ username })LocalStrategy 内的bcrypt.compareSync比对Hashing Your Passwords依赖user.password哈希相应依赖声明passport、passport-local、bcrypt各章节需写在各自文件顶部拆分完成后server.js理想状态下只剩三类职责初始化 Express 应用与中间件Pug、session、passport 初始化、myDB数据库连接与 catch 兜底路由、以及调用routes(app, myDataBase)和auth(app, myDataBase)两行“装配”代码。五、测试如何验证重构结果课程对server.js的自动化检查原文# --hints--一节包含两条正则断言值得逐条解读const url new URL(/_api/server.js, code); const res await fetch(url); const data await res.text(); assert.match( data, /require\s*\((|)\.\/routes(\.js)?\1\)/gi, You should have required your new files ); assert.match( data, /client\s*\.db[^]*routes/gi, Your new modules should be called after your connection to the database );第一条断言/require\s*\((|)\.\/routes(\.js)?\1\)/gi要求server.js中出现require(./routes)或require(./routes.js)单双引号均接受验证第 2 步的引入确实存在。第二条断言/client\s*\.db[^]*routes/gi更微妙[^]*是“任意字符含换行”的匹配写法它要求client.db数据库连接回调中获取集合的那段代码呼应前文client.db(database).collection(users)在文本上必须先于routes即routes(app, myDataBase)调用出现——这正是用静态正则来近似检查“模块实例化发生在数据库连接之后”这一时序要求。如果本地调试遇到报错课程原文建议参考其论坛中给出的完成版项目示例原文档内含论坛链接此处按规范不再外链对照示例检查依赖声明与调用位置即可。六、为什么这次拆分为后续章节铺路拆分不是终点而是铺垫。紧随其后的 Implementation of Social Authentication 要求“在routes.js文件中”新增/auth/github与/auth/github/callback两条路由其自动化测试甚至直接请求/_api/routes.js文件内容、用正则验证passport.authenticate与github及failureRedirect的存在。也就是说后续新路由一律进routes.jsserver.js不再膨胀若未做本练习的拆分Social Authentication 章节的测试将因找不到routes.js而无法通过工厂函数签名(app, myDataBase)保持不变新路由无需任何额外的接线成本。七、常见出错点自查清单结合原文要求与测试断言重构后建议按以下清单自查server.js顶部是否有require(./routes.js)/require(./auth.js)——缺任何一条都会触发第一条正则断言失败routes(app, myDataBase)与auth(app, myDataBase)是否写在myDB(async client {...})回调内、client.db(...)拿到myDataBase之后——否则第二条时序断言失败且运行期会出现“undefined 集合上调用 findOne”一类错误server.js中是否只剩 catch 块那条路由其余路由是否全部移除routes.js顶部module.exports行之上是否补齐了passport、express相关等依赖auth.js顶部是否补齐passport、passport-local、bcrypt等依赖ensureAuthenticated是否已随路由迁入routes.js且在/profile等路由中仍正常工作反复提交测试直到无报错——原文的收尾指令即 “Keep adding them until no more errors exist”。八、涉及文件索引本练习原文课程题目、要求与测试curriculum/challenges/english/blocks/advanced-node-and-express/589690e6f9fc0f352b528e6e.md课程块章节顺序curriculum/structure/blocks/advanced-node-and-express.json前序相关练习Set up Passport、Implement the Serialization of a Passport User、Authentication Strategies、Registration of New Users、Hashing Your Passwords后序相关练习Implementation of Social Authentication以上文件均为 freeCodeCamp 课程数据challenge markdown 与块结构 json学习者按课程环境运行练习时可在课程界面中按章节顺序打开对照阅读。【免费下载链接】freeCodeCampfreeCodeCamp.orgs open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考