ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

迷你留言板实战:用 Express 与模板引擎从零搭建 POST 表单数据流

迷你留言板实战:用 Express 与模板引擎从零搭建 POST 表单数据流 迷你留言板实战用 Express 与模板引擎从零搭建 POST 表单数据流【免费下载链接】curriculumThe open curriculum for learning web development项目地址: https://gitcode.com/GitHub_Trending/cu/curriculum导读本文是 Express 学习路径中的第一个动手项目在不引入数据库的前提下用express-generator搭建一个迷你留言板Mini Message Board。你将亲手实现两条路由首页/与发帖表单/new、在内存数组中存取消息、通过req.body读取表单数据并借助res.redirect(/)完成提交后的页面跳转。读完本文你将完整掌握 Express 中GET 渲染页面 → POST 接收数据 → 数据回流到视图的最小可运行闭环为后续接入数据库、实现 CRUD 打下基础。项目定位学完 Express 基础后的第一个玩具应用本课程位于 archive/nodeJS/express_and_mongoose/ 目录下属于 Express 与 Mongoose 学习段的早期练习。在它之前你已经通过 introduction_to_express.md 了解了 Node 与 Express 的关系、路由处理器与中间件的概念并通过 express_101.md 学会了用express-generator生成项目骨架、理解req/res/next三个中间件参数。项目的目的很纯粹把前面学到的知识组合成一个可以运行的交互式 Web 应用——用户访问首页看到消息列表通过表单提交新消息提交后消息立即出现在首页。这个阶段刻意不引入数据库消息只存在内存数组里重启服务即清空但它完整覆盖了服务器端表单处理这一最核心的 Web 开发范式。说明该课程在仓库中存在新旧两个版本。本文以存档版 project_mini_message_board.md 的任务步骤为主体同时融合新版 nodeJS/express/project_mini_message_board.md 中补充的关键细节如express.urlencoded()中间件、消息详情页扩展任务使方案更完整、可直接运行。一、项目初始化脚手架与版本管理1. 使用 express-generator 搭建骨架项目的第一步是生成一个可运行的 Express 工程。课程给出的方式是使用express-generator并自由选择模板引擎Pug前身 Jade缩进式语法与 HTML 差异大有一定学习曲线EJS与 Rails 的erb极为相似可以继续书写近似 HTML 的模板Handlebars强调逻辑与展示分离的语义化模板。如果你愿意也可以完全手动搭建——无非是手动创建package.json、安装express与模板引擎、建立routes/与views/目录。无论哪种方式最终的项目结构都应符合 express_101.md 中描述的 Express 标准布局。2. 初始化 Git 仓库与 .gitignore生成项目后立即在项目根目录初始化版本控制git init然后创建.gitignore文件至少包含node_modulesnode_modules这是必须养成的习惯express_101.md 的 Using Git 一节明确提醒——node_modules体积巨大且可由npm install随时重建绝不应进入版本库。二、路由规划首页与发帖表单本项目只有两条路由路径HTTP 方法作用/GET渲染首页列出所有消息/newGET渲染发帖表单页面/newPOST接收表单数据写入消息数组express-generator已经为首页创建好了路由器文件routes/index.js其中自带一个渲染 index 视图的router.get(/)处理器。我们后续要做的就是在这个文件上添加数据与新的路由。三、内存数据层messages 数组在routes/index.js的顶部模块作用域创建一个messages数组并放入两条示例消息const messages [ { text: Hi there!, user: Amando, added: new Date() }, { text: Hello World!, user: Charles, added: new Date() } ];每条消息是一个普通对象包含三个字段text消息正文user发布者名字added添加时间使用new Date()生成Date对象。把数组放在模块顶层而非路由处理器内部是为了让多条路由共享同一份数据GET 路由读取它、POST 路由向它push新消息。这实际上是内存版数据库——与后续课程中用 Mongoose 操作 MongoDB 的 express_102_crud_and_mvc.md 形成对照这里没有 Model 层数组即存储。四、首页视图用模板循环渲染消息1. 通过 locals 对象把数据交给模板要让模板拿到消息数据必须在渲染时把数组放进res.render的 locals 参数中res.render(index, { title: Mini Messageboard, messages: messages });res.render(view, locals)的第二个参数就是模板的上下文title用于页面标题messages用于消息列表循环。这是 Express 视图渲染的标准姿势也是 express_104_view_templates.md 中视图由控制器提供的数据驱动的具体体现。2. 在模板中循环输出在views/目录下的 index 模板中使用所选模板引擎的循环语法遍历messages对每条消息展示用户、正文与添加时间。以 EJS 为例ul % messages.forEach((message) { % li strong% message.user %/strong: % message.text % em(% message.added %)/em /li % }); % /ul注意在 Express 中应使用% %输出转义后的内容避免用户输入被当作 HTML 解析XSS 风险。关于转义输出的深入讨论可参考 nodeJS/express/forms_and_data_handling.md 的 Escaping user input 一节。五、发帖表单GET 渲染、POST 提交1. 添加 /new 的 GET 路由与 form 模板在routes/index.js中新增 GET 路由指向名为form的模板router.get(/new, (req, res) { res.render(form); });然后在views/目录创建form模板包含一个标题、两个输入框作者名与消息正文以及一个提交按钮。表单必须同时声明method和action才能发起网络请求form methodPOST action/new label foruserYour name/label input typetext nameuser iduser required label formessageTextYour message/label input typetext namemessageText idmessageText required button typesubmitSubmit/button /form关键点在于methodPOST指定使用 POST 动词提交数据放在请求体而非 URL 中更安全是创建/更新数据的标准选择参见 nodeJS/express/forms_and_data_handling.md 的表单概览action/new数据提交到的服务端地址输入框的name属性决定了数据在req.body中的字段名——input namemessageText的值将以req.body.messageText的形式出现在服务端。2. 添加 /new 的 POST 路由处理提交当点击提交按钮后浏览器会向action指定的 URL 发送 POST 请求。回到routes/index.js添加对应的router.post(/new)处理器router.post(/new, (req, res) { const messageText req.body.messageText; const messageUser req.body.user; messages.push({ text: messageText, user: messageUser, added: new Date() }); res.redirect(/); });3. 关键中间件express.urlencoded()要读取req.body必须先在应用层面注册表单解析中间件。浏览器提交表单时使用Content-Type: application/x-www-form-urlencoded而 Express 默认无法解析该数据。解决办法是在应用设置中加入app.use(express.urlencoded({ extended: true }));这行代码会让 Express 解析请求体并把解析后的字段对象挂载到req.body上。extended: true允许解析嵌套对象等更灵活的数据结构若设为false则只接受字符串或数组。新版课程文档 nodeJS/express/project_mini_message_board.md 专门补充了这一细节因为没有它req.body将是空对象{}表单数据无法到达处理器。这也是中间件机制的典型应用如 express_101.md 所述中间件是夹在请求与响应之间的函数按注册顺序依次执行express.urlencoded()正是负责预处理请求体的内置中间件。4. Post/Redirect/Get 模式router.post()的最后一步调用res.redirect(/)将用户送回首页。这并非可有可无的细节而是表单处理的经典模式Post/Redirect/GetPRGPOST 处理器处理完数据后不直接渲染页面而是发送 302 重定向让浏览器再发起一次 GET 请求。这样做的核心价值是防止用户刷新页面时重复提交同一表单重复 POST。nodeJS/express/forms_and_data_handling.md 的 Form handling process 一节对此有明确阐述。六、联调验证完整的请求生命周期至此整个应用的请求流如下用户访问/router.get(/)渲染 index 视图循环展示messages数组中的消息用户在首页点击新建消息链接建议在 index 模板中添加a href/new进入/new用户填写表单并提交浏览器向/new发送 POST 请求请求体为userxxxmessageTextyyyexpress.urlencoded()中间件解析请求体并填充req.bodyrouter.post(/new)读取req.body构造新消息对象push进messages数组res.redirect(/)将浏览器重定向回首页此时首页重新渲染新消息已经出现在列表中。从路由匹配的角度看这正对应 nodeJS/express/routing.md 所讲的HTTP 动词 路径的匹配规则router.get(/new)与router.post(/new)路径相同但动词不同是两条互不干扰的路由。而 CRUD 的对应关系中POST对应创建Create——本项目的表单提交正是最小的 Create 操作参见 express_102_crud_and_mvc.md。七、扩展练习消息详情页新版课程要求新版课程在核心任务之外增加了一项扩展为每条消息添加一个 open 按钮或链接点击后打开一个新页面展示该消息的详细内容。这需要利用 Express 的路由参数能力。在routes/index.js中添加带:messageId参数的路由router.get(/message/:messageId, (req, res) { const message messages[req.params.messageId]; res.render(message, { message }); });如 nodeJS/express/routing.md 所述路径中以:开头的段是路由参数Express 会自动把实际值填充到req.params对象中例如访问/message/0时req.params.messageId为0。视图模板中再渲染message.text、message.user、message.added即可。这个练习帮助你提前熟悉根据标识读取单条记录的服务端模式是后续 CRUD 项目中Read 单个资源的雏形。八、完成标准与后续衔接项目的完成标准是能够访问/new首页上有入口链接、填写并提交表单、然后在首页看到新消息出现在消息列表中。这是对以下能力的综合检验使用express-generator搭建项目并管理依赖在路由模块中维护共享数据内存数组用模板引擎循环渲染列表配置express.urlencoded()解析表单用router.get/router.post组织路由用res.redirect完成 PRG 跳转。完成后记得把项目推到 GitHub。下一课将学习如何把应用部署到线上可参考同目录下的 deployment.md届时可以把留言板链接到课程的学生解决方案列表中展示。这个项目虽然玩具味十足但它亲手验证了 Express 应用中数据从浏览器表单流经中间件、路由处理器最终回流到视图的完整链路——这正是后续所有数据驱动应用包括 project_inventory_application.md 等大型项目的地基。【免费下载链接】curriculumThe open curriculum for learning web development项目地址: https://gitcode.com/GitHub_Trending/cu/curriculum创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表