前端到后端:从 Vite 到 Express❗
引言
路由:前端与后端
从源到服务器
开发与生产:
订单处理:快递中的关键路径管理
结论❤️
引言
大家好!🤗 如果你是后端开发新手,或者你已经掌握了一些基础知识,但想更深入地了解服务器背后的逻辑、请求路由以及所有这些基础概念,我真心希望这篇文章能对你有所帮助。🥰
一开始感到困惑或者无法立即理解所有内容都是完全正常的,你最终会在合适的时机弄明白!或许这篇文章能帮你解惑,或许只是印证了你已经知道的事情!
我们将讨论以下概念:
路由:前端与后端
路由是指当用户访问特定URL(路径或“路由”)时,决定返回哪段代码或哪个页面。这正是这两个世界之间的第一个主要区别。
前端路由(Vite、React Router)
当我们使用现代前端框架(例如 React with Vite 或 Create React App)时,我们不需要处理静态文件的路由:
→开发服务器非常智能:Vite 的开发服务器旨在帮助我们快速编写代码。它能够读取我们的源文件(位于 `<path>` 目录下的文件src/),并自动将其发布到相应的 URL 下。
→自动路由:如果我们的 HTML 或 React 代码引用了某个文件/styles/main.css,Vite 服务器会立即知道在哪里找到该文件(在其内存或文件系统中),并立即将其发送到浏览器。我们无需为此编写任何特殊代码❗
→专注于应用逻辑:使用 React Router 等库,我们只需关注应用逻辑(例如,“如果 URL 是 [URL] /profile,则显示个人资料组件”)。路由在浏览器中进行,在 JavaScript 文件加载完毕之后。
后端手动路由(Express.js)
Express.js 只是一个极简框架。它没有任何假设,也没有任何内置的“魔法”。
→路由是手动的:一旦我们将 Express.js 设置为主服务器,我们就必须明确地告诉它如何处理到达它的每个请求。
我们是否希望POST /api/login请求验证数据库中的密码❓ 我们必须写app.post('/api/login',...)。
我们是否希望GET /api/users请求返回用户列表❓ 我们必须这样写app.get('/api/users', ...)。
→静态文件识别错误/main.css:如果没有明确指示, Express在收到对静态文件的请求时,无法识别这是一个静态文件。它会查找 API 路由或渲染逻辑。由于找不到,它会隐式返回404 Not Found 错误。
在启动时,Vite 开发服务器会默默地执行一些神奇的操作,它会自动处理所有静态文件(如 CSS 和图像)的路由和提供,直接从内存中读取。
然而,当我们引入 Express.js 时,一切就变得复杂了。Express 并不具备这种特性,它需要明确的指令。我们必须手动定义 API 路由app.get('/api/data'),更重要的是,我们必须使用 express.static()`<script>`标签手动告诉 Express:“这里存放着网页所需的所有静态文件。” 如果没有这一步手动操作,服务器将无法访问我们的 CSS 和 JavaScript 文件,从而导致页面无法正常显示!
从源到服务器
开发中的静态文件:
在开发过程中,当我们运行npm run devReact 项目时:
→无物理文件夹:Vite 服务器直接从目录读取文件( .jsx, )并将其保存在 RAM(内存)中。它不会创建存放编译文件的物理文件夹。.csssrc/
→速度:我们保存的任何更改都会通过 HMR(热模块重载)立即传输到浏览器,从而使编码体验流畅。
→尚未准备好投入生产:虽然速度很快,但这种模式不稳定、不安全,也没有针对互联网上成千上万的真实用户进行优化。
从源到分发:
何时以及为何需要编译❓ 在发布应用程序(上线生产环境)之前,我们必须编译代码:
→命令:npm run build。
→优化:此命令获取我们所有的源文件(React,,CSS等),对其进行压缩(使其体积小得多),将它们连接起来(将它们放入更少的包中),并对其进行优化以获得最大的加载速度。
→结果dist:所有这些优化后的文件都被放入一个新的物理文件夹中,通常称为 `.fs`dist或 `.fs` 。该文件夹包含前端的build最终静态版本,随时可以提供服务。
进入express.static():
→如何提供 dist 文件夹?❓ 现在我们有了优化后的 dist 文件夹,我们必须告诉 Express(后端)它需要公开提供的文件夹:
→解决方案是express.static():这行代码是我们给 Express 服务器的指令:
// in production, Express serves the frontend's 'dist' folder
app.use(express.static(path.join(__dirname, 'client/dist')));
→工作原理:每当服务器收到HTTP 请求,且请求路径与我们定义的API 路由不匹配(例如,不以 `/` 开头/api)时,Express 都会在dist 文件夹中查找!如果找到与请求 URL 匹配的文件(例如,`/` /style.css),它会立即将该文件发送给客户端,并停止路由过程!
开发与生产:
npm run dev→ 如果我们在前端(React)和后端(Express)项目目录中都看到了同一个命令,我们可能会认为它们的作用相同。但事实并非如此❗这是一个至关重要的区别,尤其是在考虑安全性和性能时。
→双服务器npm run dev:两台服务器,两种用途
当我们谈到开发模式(Dev)和生产模式(Prod)时,我们是在描述我们正在运行的代码的状态和目的。
开发模式(我们的工作台):
开发模式是我们的工作台,它针对速度和调试进行了优化。
→目的:唯一目标是促进快速编码、测试和调试。
→前端设置:服务器在一个端口上运行Vite 开发服务器(例如5173)。
→后端工具:我们使用诸如 之类的工具,以便在保存更改后nodemon立即自动重启服务器。
→错误:错误信息清晰详细(堆栈跟踪),并直接打印到您的控制台,帮助您立即解决问题
。 →优化:文件按原样提供,仅进行最小程度的优化,因为文件大小和速度并非主要考虑因素。
生产模式(线上公共服务器)
生产模式是最终的、经过优化的版本,面向公众发布,其设计注重稳定性和安全性。
→目的:旨在为用户提供稳定、快速且安全的
体验。 →前端设置:前端代码首先经过构建(编译和压缩),然后由单个Express 服务器在其指定端口(例如 8080 3000)上提供服务。
→后端工具:我们使用高度优化的进程管理器(例如 PM2)来确保服务器持续稳定运行。 →错误:错误会在内部记录,但绝不会向公众用户显示,从而防止安全漏洞。
→优化:文件经过高度压缩和积极缓存,以实现 最佳性能,并为所有用户提供更快的加载速度。
安全风险:
为什么我们不在生产环境中运行开发模式❓
在运行中的公共服务器上以开发模式运行 Express 服务器是一个重大的安全漏洞,强烈不建议这样做。
→安全漏洞:开发错误通常会泄露敏感数据,例如服务器上的文件路径、环境变量,甚至数据库结构的细节。将这些信息泄露给攻击者是一个严重的安全漏洞❗
→性能:开发模式旨在提供便利,而非追求速度。在实际用户负载下,您会遇到响应速度慢、资源管理不善以及可扩展性有限等问题。
→稳定性:类似这样的工具nodemon会在每次保存更改时重启代码。对于需要 24/7 全天候运行的面向公众的应用程序来说,这种行为不可预测且极不稳定❗
订单处理:快递中的关键路径管理
现在,让我们来看看设置路由和中间件的关键过程,确保 Express 能够正确处理所有请求。
中间件的作用:app.use()
在 Express 中,中间件就是一个在请求-响应周期中执行的函数。它可以访问请求对象req、响应对象res以及周期中的下一个函数。next
→ app.use(middleware):此方法主要用于注册中间件。它会对所有HTTP方法(GET、、POST等)和所有路径执行提供的函数(除非我们指定路径前缀)。
→黄金法则:中间件必须按照代码中定义的顺序执行。一旦某个中间件发送了响应(例如,`response.getResponse() res.send('Hello')`),循环就会停止,后续的中间件或路由处理程序都不会执行❗
流程示例顺序:
app.use(cors)app.use(express.json)app.use('/api', apiRouter)app.use(express.static(dist_path))<- 这是关键的分离点❗- ……其他路线……
React Router 的陷阱:
为什么我们需要❓这是将我们的后端逻辑与前端app.get('*')应用程序连接起来的最后一块拼图。
→用途:该app.get('*')路由是通配符处理程序。它使用通配符*来匹配任何GET尚未被之前定义的任何中间件或路由处理的请求。
→场景:当用户mysite.com/profile在浏览器中输入类似这样的直接链接时,服务器会收到对该链接的请求/profile。
- Express检查路线
API(例如,/api)。未找到匹配项❗ - 快速检查
express.static()名为 profile 的文件。未找到匹配项。❗ - 该请求归于……
app.get('*')
→解决方案:我们告诉 Express 对于任何未匹配的路径,直接提供主应用程序文件(index.html)。
app.get('*', (req, res) => {
// we tell Express: "Send the HTML file and let React Router handle the URL."
res.sendFile(path.resolve(FRONTEND_BUILD_PATH, 'index.html'));
});
→结果:浏览器加载index.html完毕,React 接管,React Router 读取/profileURL 并显示正确的组件,从而实现流畅的单页应用体验❗
结论❤️
如果你是后端开发新手,一开始没能理解这些概念,别灰心,它们一开始确实会让人困惑。我想我们刚开始的时候都遇到过这些问题……我肯定也遇到过!🙃
主要挑战在于我们需要转变思维方式,从像 Vite 这样的前端工具的自动内存服务,转变为 Express更手动、更结构化的路由方法。
希望这篇文章对你有所帮助,或者能让你想起当初后端开发初期遇到的种种困难。🤗我很好奇有多少人一开始
也经历过同样的迷茫,如果你也曾被后端开发困扰过,请在评论区留言!我很想知道自己并非孤身一人。🤗🥰
祝您阅读愉快!如果这篇文章对您有帮助或您觉得有用,请点个赞哦!🤗
更多文章:
Node.js——构建你的第一个服务器的步骤❗
我的第一个Node.js:掌握基础知识❗

