从 LAMP 到前后端分离:架构演进与技术实践

目录

  1. 1. LAMP 架构<span class=<h-char class=“bd bd-beg“>“bd-box<h-char class=“bd bd-beg“>“><h-char class=“bd bd-beg“>:传统 Web 开发的基石
  2. 2. 前后端分离的诞生<span class=<h-char class=“bd bd-beg“>“bd-box<h-char class=“bd bd-beg“>“><h-char class=“bd bd-beg“>:解耦与协作的必然
  3. 3. 前后端分离的实践要点
    1. 3.1. 接口规范与协作模式
    2. 3.2. 技术架构设计
    3. 3.3. 性能优化
  4. 4. 从 LAMP 到分离架构的演进示例
  5. 5. 挑战与解决方案
  6. 6. 总结
  7. 7. 拓展<span class=<h-char class=“bd bd-beg“>“bd-box<h-char class=“bd bd-beg“>“><h-char class=“bd bd-beg“>:CentOS快速部署LAMP
    1. 7.1. 1. 更新系统组件
    2. 7.2. 2. 安装 Apache
      1. 7.2.1. 配置防火墙<span class=<h-char class=“bd bd-beg“>“bd-box<h-char class=“bd bd-beg“>“>(若开启<span class=<h-char class=“bd bd-beg“>“bd-box<h-char class=“bd bd-beg“>“><h-char class=“bd bd-beg“>)
    3. 7.3. 3. 安装 MySQL/MariaDB
      1. 7.3.1. 方案 1<span class=<h-char class=“bd bd-beg“>“bd-box<h-char class=“bd bd-beg“>“><h-char class=“bd bd-beg“>:安装 MariaDB<span class=<h-char class=“bd bd-beg“>“bd-box<h-char class=“bd bd-beg“>“>(推荐<span class=<h-char class=“bd bd-beg“>“bd-box<h-char class=“bd bd-beg“>“><h-char class=“bd bd-beg“>)
      2. 7.3.2. 方案 2<span class=<h-char class=“bd bd-beg“>“bd-box<h-char class=“bd bd-beg“>“><h-char class=“bd bd-beg“>:安装 MySQL 8.0<span class=<h-char class=“bd bd-beg“>“bd-box<h-char class=“bd bd-beg“>“>(需添加官方仓库<span class=<h-char class=“bd bd-beg“>“bd-box<h-char class=“bd bd-beg“>“><h-char class=“bd bd-beg“>)
    4. 7.4. 4. 安装 PHP
      1. 7.4.1. 安装基础 PHP 版本
      2. 7.4.2. 验证 PHP
    5. 7.5. 5. 验证 LAMP 环境
      1. 7.5.1. 测试数据库连接
    6. 7.6. 6. 可选优化
      1. 7.6.1. 配置虚拟主机
    7. 7.7. 常见问题解决
    8. 7.8. 总结

LAMP 架构<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>传统 Web 开发的基石

在早期的 Web 开发领域<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>LAMP 架构犹如一座坚固的基石<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>支撑起无数动态网站的构建<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>LAMP<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>即 Linux + Apache + MySQL + PHP/Perl/Python<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>是一组开源软件的组合<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>它们协同工作<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>为 Web 应用提供了完整的运行环境<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

随着移动互联网的迅猛发展<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>用户对于应用的体验和功能需求变得更加多样化和复杂<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>在这个背景下<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>传统的 LAMP 架构逐渐显得力不从心<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>其局限性愈发凸显<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这也促使了前后端分离模式的诞生<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>成为 Web 开发领域的一次重要变革<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

以一个简单的聊天室系统为例<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>我们可以清晰地看到 LAMP 架构的工作原理<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>Linux 作为操作系统<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>为整个系统提供了稳定可靠的运行基础<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>管理着硬件资源和进程调度<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>Apache 则充当着 Web 服务器的角色<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>负责接收来自客户端的 HTTP 请求<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>当用户在浏览器中输入聊天室的网址并发送请求时<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>Apache 首先接收到这个请求<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>如果请求的是静态页面<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>比如聊天室的 HTML 页面布局<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>CSS 样式文件或者图片等<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>Apache 会直接从服务器的文件系统中读取这些文件<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>并将其返回给浏览器<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>以展示给用户<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

LAMP 架构之所以在早期广受欢迎<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>是因为它具有诸多显著的优势<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>从成本角度来看<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>由于其所有组件均为开源软件<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这意味着开发者无需支付高昂的软件授权费用<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>大大降低了开发成本<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>尤其适合预算有限的中小型项目<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>开发速度也是 LAMP 的一大亮点<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>其成熟的生态系统提供了丰富的开发工具<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>框架和大量的开源代码库<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>开发者可以借助这些资源快速搭建项目框架<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>减少从头开发的工作量<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>提高开发效率<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>例如<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>使用 PHP 的一些框架<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>如 Laravel<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>Yii 等<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>可以更方便地进行数据库操作<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>路由管理和视图渲染<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

然而<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>随着技术的发展和应用场景的日益复杂<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>LAMP 架构的局限性也逐渐暴露出来<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>最明显的问题就是前后端代码耦合严重<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>在 LAMP 架构中<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>PHP 代码常常直接嵌入 HTML 中<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这使得前端页面的展示逻辑和后端的业务逻辑混合在一起<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>代码结构不清晰<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>维护和扩展难度较大<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>当需要修改页面的某个功能时<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>可能需要同时在 PHP 代码和 HTML 代码中进行查找和修改<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>容易出现错误<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>而且职责划分不够明确<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>后端不仅要处理复杂的业务逻辑<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>还要负责页面的渲染工作<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这使得后端的负担较重<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>不利于系统的性能优化和功能扩展<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

在如今多终端设备共存的时代<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>LAMP 架构难以适应多终端需求的问题也愈发突出<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>不同终端设备<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>如移动端和 PC 端<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>具有不同的屏幕尺寸<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>分辨率和交互方式<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>需要独立开发适配的页面<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>但在 LAMP 架构下<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>前后端紧密耦合<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>很难实现一套代码在不同终端上的高效复用<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>往往需要为每个终端单独开发和维护一套代码<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>增加了开发成本和维护难度 <span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

前后端分离的诞生<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>解耦与协作的必然

在移动互联网时代<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>各种智能设备层出不穷<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>如智能手机<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>平板电脑等<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>用户期望在不同终端上都能获得一致且优质的应用体验<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>然而<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>LAMP 架构中前后端代码的紧密耦合以及职责不清的问题<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>使得开发和维护多终端适配的应用变得异常困难<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>例如<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>当需要为移动端开发一个适配版本的聊天室应用时<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>由于 LAMP 架构下前后端代码的混合<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>可能需要对整个代码库进行大规模的修改和调整<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>不仅工作量巨大<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>而且容易引入新的问题<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>而且<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>随着业务的增长和功能的不断增加<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>LAMP 架构下的项目代码变得越来越臃肿<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>开发和维护的难度呈指数级上升<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>开发效率大幅降低<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

前后端分离模式正是为了解决这些问题而应运而生<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>其核心思想在于更加清晰明确的职责划分<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>前端专注于视图<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>>View<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>和交互逻辑<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>>Controller<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg><h-char class=bd bd-beg>负责与用户进行直接交互<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>提供直观<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>流畅的用户体验<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>它通过各种前端技术和框架<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>如 React<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>Vue<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>Angular 等<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>构建出丰富多样的用户界面<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>实现页面的动态展示和交互效果<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>后端则专注于数据接口<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>>Model<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg><h-char class=bd bd-beg>负责处理业务逻辑<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>数据存储和管理<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>以及提供稳定可靠的数据接口<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>后端通过使用各种服务器端技术和框架<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>如 Spring Boot<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>Django<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>Flask 等<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>高效地处理大量的业务请求<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>保障数据的安全和完整性<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

这种模式还实现了技术栈的独立<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>前端团队可以根据项目需求和自身技术优势<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>自由选择适合的前端框架和工具<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>不断追求更好的用户界面和交互效果<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>后端团队也能够专注于后端技术的优化和业务逻辑的实现<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>选择最适合的服务器端语言<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>数据库和框架<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>以提高系统的性能和稳定性<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>前后端之间通过标准的接口进行通信<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>通常是 RESTful API<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这种方式使得前后端的交互更加规范<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>清晰<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>也便于维护和扩展<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

以电商平台为例<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这种前后端分离模式的优势体现得淋漓尽致<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>在前端<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>使用 React 或 Vue 等框架构建用户界面<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>能够快速实现商品列表的展示<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>购物车的交互以及用户订单的管理等功能<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>用户在浏览商品时<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>能够感受到流畅的页面切换和实时的交互反馈<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>大大提升了购物体验<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>后端采用 Spring Boot 等框架搭建服务<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>提供商品查询<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>订单处理<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>库存管理等各种 API 接口<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这些接口能够高效地处理大量的请求<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>保障数据的准确性和一致性<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

引入 Node.js 中间层进一步优化了整个架构<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>Node.js 可以聚合多个后端接口<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>例如将物流信息接口<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>促销信息接口等进行整合<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>减少前端与后端之间的多次请求<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>优化无线端性能<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>当用户查看商品详情时<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>Node.js 中间层可以一次性获取商品的基本信息<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>物流信息以及当前的促销活动信息<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>然后统一返回给前端<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>减少了 HTTP 请求次数<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>提高了页面的加载速度<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>为用户提供了更好的购物体验 <span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

前后端分离的实践要点

接口规范与协作模式

在前后端分离的架构中<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>接口规范与协作模式是确保项目顺利进行的关键环节<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>其中<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>RESTful API 以其简洁<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>规范的设计风格<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>成为了前后端通信的首选方式<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>它严格遵循 HTTP 协议<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>使用标准的 HTTP 方法来操作资源<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>使得接口的语义更加清晰<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>易于理解和维护<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>例如<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>对于一个电商平台的商品管理模块<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>我们可以通过GET /api/products来获取所有商品的列表<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>GET /api/products/{id}获取特定商品的详细信息<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>POST /api/products用于创建新的商品<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>PUT /api/products/{id}则用于更新指定商品的信息<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>DELETE /api/products/{id}用于删除商品<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这种统一的接口设计方式<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>使得前端开发者能够清晰地知道每个接口的功能<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>后端开发者也能更方便地实现和维护这些接口 <span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

**前后端分离架构图**

在开发过程中<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>由于前端和后端的开发进度可能不一致<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>为了避免前端开发因等待后端接口而受阻<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>Mock 数据就发挥了重要作用<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>前端可以通过 Mock Server<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>如 Postman 等工具<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>模拟后端接口返回的数据<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>在开发商品详情页面时<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>后端的商品数据接口可能还未完成<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>但前端可以使用 Mock Server 创建一个模拟接口<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>返回预设的商品数据<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>包括商品名称<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>价格<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>描述<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>图片等信息<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这样<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>前端开发者就可以按照正常的流程进行页面开发和交互逻辑的实现<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>提高开发效率<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>当后端接口开发完成后<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>只需将 Mock 数据替换为真实的接口数据<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>进行简单的联调即可<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

为了确保前后端对接口的理解一致<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>使用专业的文档工具来生成接口文档是必不可少的<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>Swagger 和 OpenAPI 就是这样的工具<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>它们能够根据后端的代码或配置自动生成详细的接口文档<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这些文档不仅包含了接口的 URL<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>请求方法<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>请求参数<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>响应数据格式等基本信息<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>还能以直观的界面展示出来<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>方便前后端开发者查阅和使用<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>例如<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>Swagger 生成的接口文档可以在浏览器中直接访问<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>通过可视化的界面<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>开发者可以清晰地看到每个接口的详细说明<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>甚至可以直接在文档页面中进行接口测试<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>大大提高了前后端协作的效率和准确性 <span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

技术架构设计

前端架构在前后端分离模式下<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>单页面应用<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>>SPA<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>成为了主流的选择<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>SPA 通过在客户端动态加载和渲染页面内容<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>实现了页面的无刷新切换<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>极大地提升了用户体验<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>SPA 在搜索引擎优化<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>>SEO<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>方面存在一定的局限性<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>由于 SPA 的页面内容是通过 JavaScript 动态生成的<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>搜索引擎爬虫在抓取页面时<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>可能无法执行这些 JavaScript 代码<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>导致页面内容无法被正确索引<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>为了解决这个问题<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>服务端渲染<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>>SSR<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>技术应运而生<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>SSR 是在服务器端生成完整的 HTML 页面<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>然后将其发送给客户端<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这样<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>搜索引擎爬虫就能够直接抓取到页面的内容<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>提高了页面的 SEO 性能<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>像 Next.js<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>>基于 React<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>和 Nuxt.js<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>>基于 Vue<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>等框架<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>就提供了很好的 SSR 支持<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>使得开发者可以方便地实现 SPA 与 SSR 的结合 <span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

SPA/SSR渲染流程对比

后端架构则趋向于微服务化<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>微服务架构将一个大型的应用程序拆分成多个小型的<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>独立的服务<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>每个服务都专注于实现单一的业务功能<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>并且可以独立部署和扩展<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>在一个大型的电商系统中<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>订单服务负责处理订单的创建<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>修改<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>查询等操作<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>商品服务负责商品的管理<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>用户服务负责用户信息的管理等<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这些服务之间通过轻量级的通信机制<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>如 RESTful API 进行交互<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>通过微服务化<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>后端架构的可维护性<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>可扩展性和灵活性都得到了极大的提升<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>每个服务可以根据自身的业务需求选择最合适的技术栈和框架<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>独立进行开发<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>测试和部署<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>不会相互影响<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

微服务架构示例

在部署方案上<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>Nginx 作为一款高性能的 Web 服务器和反向代理服务器<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>发挥着重要的作用<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>它可以反向代理前端的静态资源<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>如 HTML<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>CSS<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>JavaScript 文件等<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>将这些资源快速地返回给客户端<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>提高页面的加载速度<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>Nginx 还可以反向代理后端的 API<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>实现负载均衡<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>当有大量的客户端请求到达时<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>Nginx 可以将这些请求均匀地分发到多个后端服务器上<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>避免单个服务器因负载过高而出现性能问题<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>从而保证整个系统的稳定性和可靠性 <span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

性能优化

性能优化是前后端分离架构中不可忽视的重要环节<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>它直接影响着用户体验和系统的可用性<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>在前端优化方面<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>代码分割是一种有效的手段<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>随着前端应用的功能不断增加<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>代码量也会越来越大<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这会导致页面加载时需要下载大量的代码<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>从而影响加载速度<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>通过代码分割<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>可以将代码按照功能模块进行拆分<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>只有在需要的时候才加载相应的代码<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>在一个电商应用中<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>商品详情页面和购物车页面的功能相对独立<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>我们可以将它们的代码分别进行打包<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>当用户访问商品详情页面时<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>只加载商品详情页面所需的代码<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>而购物车页面的代码在用户进入购物车时才进行加载<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这样可以显著减少首屏加载的时间<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

前后端优化架构图

CDN<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>>内容分发网络<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>加速也是前端优化的常用方法<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>CDN 通过在全球各地部署节点服务器<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>将前端的静态资源缓存到离用户最近的节点上<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>当用户请求这些资源时<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>CDN 服务器可以快速地将资源返回给用户<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>大大提高了资源的加载速度<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>对于一些常用的前端库<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>如 Vue.js<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>React.js 等<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>我们可以将它们托管到 CDN 上<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>而不是放在自己的服务器上<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这样<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>用户在访问应用时<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>就可以从离自己最近的 CDN 节点获取这些库<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>减少了网络传输的延迟<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

懒加载技术则是针对页面中的图片<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>组件等元素进行优化<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>在页面加载时<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>只加载当前可见区域的元素<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>而对于那些暂时不可见的元素<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>等到用户滚动页面使其可见时再进行加载<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>在一个图片展示页面中<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>可能有大量的图片<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>如果一次性全部加载<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>会导致页面加载缓慢<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>通过懒加载技术<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>只有当用户滚动到图片所在区域时<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>图片才会被加载<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这样可以有效地减少页面初始加载的资源量<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>提高页面的加载速度<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

后端优化同样至关重要<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>缓存策略是提高后端性能的关键<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>Redis 作为一种高性能的内存缓存数据库<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>被广泛应用于后端缓存<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>我们可以将一些经常被查询且不经常变化的数据<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>如商品的基本信息<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>热门文章等<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>缓存到 Redis 中<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>当有请求到来时<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>后端首先从 Redis 中查询数据<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>如果缓存中存在数据<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>则直接返回给前端<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>避免了重复查询数据库<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>大大提高了响应速度<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>只有当缓存中没有数据时<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>才去查询数据库<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>并将查询结果存入缓存中<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>以便下次查询使用<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

随着数据量的不断增加<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>数据库分库分表也是后端优化的重要手段<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>当一个数据库中的数据量过大时<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>查询和写入的性能都会受到影响<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>通过分库分表<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>可以将数据分散存储到多个数据库或表中<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>减轻单个数据库或表的压力<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>在一个电商系统中<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>订单数据量可能非常大<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>我们可以按照时间或订单 ID 等条件<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>将订单数据分表存储<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>每个表只存储一定时间段或一定范围内的订单数据<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这样<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>在进行订单查询时<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>可以根据查询条件快速定位到对应的表<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>提高查询效率<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

Node.js 中间层在性能优化方面也有着独特的作用<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>它可以合并接口请求<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>减少前端与后端之间的 HTTP 请求次数<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>以淘宝详情页为例<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>页面中可能需要展示商品的基本信息<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>价格<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>库存<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>评论<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>促销活动等多种数据<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这些数据可能来自不同的后端接口<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>通过 Node.js 中间层<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>可以将这些接口请求进行合并<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>一次性获取所有需要的数据<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>然后统一返回给前端<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这样不仅减少了 HTTP 请求次数<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>降低了网络传输的开销<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>还提高了页面的加载速度<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>为用户提供了更好的购物体验 <span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

从 LAMP 到分离架构的演进示例

为了更直观地理解从 LAMP 到前后端分离架构的演进<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>我们以聊天室系统为例<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>对比这两种架构下的实现方式及其带来的价值<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

在 LAMP 架构中<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>以 PHP 语言为例<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>实现聊天室系统时<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>代码往往呈现出前后端紧密耦合的状态<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>PHP 直接生成 HTML 的方式在早期聊天室开发中较为常见<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>以下是一段简单的示例代码<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"highlight php"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"code"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"meta"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"><?php
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">// 连接数据库
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"variable"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">$conn = "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_ invoke__"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">mysqli_connect("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"localhost", "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"username", "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"password", "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"chat_database");
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">// 查询聊天记录
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"variable"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">$messages = "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_ invoke__"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">mysqli_query("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"variable"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">$conn, "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"SELECT * FROM chat");
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">// 循环输出聊天记录
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">while ("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"variable"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">$row = "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_ invoke__"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">mysqli_fetch_array("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"variable"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">$messages)) {
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">echo "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"<div>"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"subst"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">{$row['content']}</div>";
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">}
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">// 关闭数据库连接
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_ invoke__"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">mysqli_close("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"variable"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">$conn);
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"meta"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">?>

在这段代码中<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>PHP 不仅负责从 MySQL 数据库中查询聊天记录<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>还直接将这些记录渲染成 HTML 格式输出到浏览器<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这种方式虽然简单直接<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>但存在诸多问题<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>当需要修改前端的显示样式或交互逻辑时<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>可能需要深入到 PHP 代码中进行修改<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>增加了开发和维护的难度<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>而且<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这种架构下<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>前端和后端的开发相互依赖<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>开发效率较低<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

而在前后端分离架构下<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>聊天室系统的实现方式有了很大的不同<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>前端可以使用 Vue 框架<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>通过 Axios 库来调用后端提供的接口获取聊天数据<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>以下是前端 Vue 代码的示例<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"highlight php"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"code"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"><template>
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> <div>
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> <div v-"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">for="bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"message in messages" :key="bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"message.id">{{ message.content }}</div>
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> <form @submit.prevent="bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"sendMessage">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> <input v-model="bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"newMessage" placeholder="bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"输入消息">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> <button type="bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"submit">发送</button>
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> </form>
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> </div>
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"></template>
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"><script>
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">import axios "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">from "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">'axios';
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">export "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">default {
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_ invoke__"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">data() {
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">return { messages: [], newMessage: "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">'' };
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> },
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_ invoke__"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">mounted() { this."bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_ invoke__"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">fetchMessages(); },
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> methods: {
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> async "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_ invoke__"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">fetchMessages() {
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">try {
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">const "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"variable constant_"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">response = await axios."bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_ invoke__"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">get("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">'/api/messages');
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> this.messages = response.data;
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> } "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">catch (error) {
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> console."bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_ invoke__"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">error("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">'获取聊天记录失败', error);
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> }
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> },
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> async "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_ invoke__"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">sendMessage() {
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">try {
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> await axios."bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_ invoke__"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">post("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">'/api/messages', { "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"attr"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">content: this.newMessage });
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> this.newMessage = "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">'';
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> this."bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_ invoke__"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">fetchMessages();
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> } "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">catch (error) {
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> console."bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_ invoke__"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">error("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">'发送消息失败', error);
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> }
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> }
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> }
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">};
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"></script>

在后端<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>使用 Spring Boot 框架来处理业务逻辑和提供数据接口<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>Spring Boot 可以方便地与数据库进行交互<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>查询和存储聊天记录<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>并将数据以 JSON 格式返回给前端<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>以下是后端 Spring Boot 的示例代码<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"highlight java"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"code"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">import org.springframework.web.bind.annotation.*;
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">import java.util.List;
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"meta"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">@RestController
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"meta"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">@RequestMapping("/api")
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">public "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">class "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title class_"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">ChatController {
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">private "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">final ChatService chatService;
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">public "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">ChatController"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"params"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">(ChatService chatService) {
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"built_in"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">this.chatService = chatService;
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> }
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"meta"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">@GetMapping("/messages")
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">public List<Message> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">getMessages"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"params"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">() {
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">return chatService.getMessages();
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> }
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"meta"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">@PostMapping("/messages")
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">public Message "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">sendMessage"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"params"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"meta"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">@RequestBody Message message) {
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">return chatService.sendMessage(message);
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> }
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">}

在前后端分离架构中<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>Node.js 可以发挥重要作用<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>特别是在处理 WebSocket 实时通信方面<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>通过 Node.js 和 WebSocket 库<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>socket.io<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>可以实现聊天室的实时消息推送<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>当有新的聊天消息时<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>后端可以通过 WebSocket 将消息实时推送给所有在线的前端客户端<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>而不需要前端频繁地发起请求获取最新消息<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>以下是使用 Node.js 和 socket.io 实现 WebSocket 实时通信的简单示例<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"highlight js"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"code"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">const express = "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"built_in"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">require("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">'express');
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">const app = "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">express();
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">const http = "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"built_in"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">require("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">'http')."bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title class_"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">Server(app);
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">const io = "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"built_in"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">require("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">'socket.io')(http);
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">// 模拟聊天消息存储
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">let messages = [];
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">io."bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">on("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">'connection', "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"function"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"params"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">socket) => {
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"variable language_"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">console."bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">log("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">'用户已连接');
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">// 发送历史消息给新连接的用户
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> socket."bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">emit("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">'history-messages', messages);
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> socket."bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">on("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">'send-message', "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"function"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"params"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">message) => {
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> messages."bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">push(message);
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> io."bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">emit("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">'receive-message', message);
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> });
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> socket."bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">on("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">'disconnect', "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"function"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">() => {
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"variable language_"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">console."bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">log("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">'用户已断开连接');
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> });
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">});
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">const port = "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"number"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">3000;
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">http."bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">listen(port, "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"function"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">() => {
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"variable language_"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">console."bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">log("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">`服务器正在运行,端口号: ${port}`);
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">});

从 LAMP 架构演进到前后端分离架构<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>带来了诸多显著的价值<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>前端可以独立进行 UI 的迭代和优化<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>根据用户需求和设计理念自由地调整页面布局<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>样式和交互效果<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>而无需担心影响后端的业务逻辑<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>后端则可以专注于处理高并发请求<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>优化数据库查询性能<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>保障系统的稳定性和可靠性<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>前后端分离使得同一套后端 API 可以被多个终端复用<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>无论是 Web 端还是 App 端<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>都可以通过调用相同的 API 获取数据<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>大大提高了开发效率和代码的复用性<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>据相关实践统计<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>采用前后端分离架构后<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>开发效率通常可以提升 30% 以上<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这使得项目能够更快地迭代和上线<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>满足市场的需求 <span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

挑战与解决方案

在从 LAMP 架构向前后端分离架构演进的过程中<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>虽然带来了诸多优势<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>但也不可避免地面临一些挑战<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>需要我们找到相应的解决方案来确保项目的顺利推进<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

跨域问题是前后端分离架构中常见的挑战之一<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>由于前后端通常部署在不同的域名或端口下<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>当前端通过 AJAX 请求后端接口时<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>浏览器会出于安全考虑<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>遵循同源策略<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>阻止这种跨域请求<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这就导致前端无法正常获取后端的数据<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>影响应用的功能实现<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>为了解决这个问题<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>一种常见的方法是在后端进行 CORS<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>>跨域资源共享<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>配置<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>以 Spring Boot 为例<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>可以通过添加 CorsConfig 配置类来实现<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>在配置类中<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>通过addCorsMappings方法定义允许跨域的路径<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>允许的源<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>允许的方法等<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这样<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>后端在接收到前端的跨域请求时<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>会在响应头中添加Access-Control-Allow-Origin等相关字段<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>告诉浏览器该请求是被允许的<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>从而解决跨域问题<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"highlight java"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"code"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">import org.springframework.context.annotation.Bean;
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">import org.springframework.context.annotation.Configuration;
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">import org.springframework.web.servlet.config.annotation.CorsRegistry;
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"meta"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">@Configuration
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">public "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">class "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title class_"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">CorsConfig {
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"meta"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">@Bean
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">public WebMvcConfigurer "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">corsConfigurer"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"params"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">() {
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">return "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">new "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title class_"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">WebMvcConfigurer() {
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"meta"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">@Override
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">public "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">void "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">addCorsMappings"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"params"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">(CorsRegistry registry) {
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> registry.addMapping("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"/**")
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> .allowedOriginPatterns("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"*")
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> .allowedMethods("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"GET", "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"POST", "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"PUT", "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"DELETE", "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"OPTIONS")
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> .allowCredentials("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"literal"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">true)
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> .maxAge("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"number"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">3600);
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> }
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> };
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> }
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">}```

也可以通过 Nginx 代理来解决跨域问题。Nginx 作为反向代理服务器,可以将前端的请求转发到后端服务器,并在转发过程中对请求和响应进行处理。在 Nginx 的配置文件中,通过proxy_pass指令将前端的请求代理到后端的真实地址,同时可以添加add_header指令来设置响应头,允许跨域请求。这样,前端通过访问 Nginx 的地址,就可以间接访问后端接口,避免了跨域问题。

```java
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">server {
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> listen "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"number"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">80;
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> server_name localhost;
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> location / {
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> proxy_pass http:"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">//backend_server;
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> add_header Access-Control-Allow-Origin *;
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> add_header Access-Control-Allow-Methods "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">'GET, POST, PUT, DELETE, OPTIONS';
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> add_header Access-Control-Allow-Headers "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">if ($request_method = "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">'OPTIONS') {
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">return "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"number"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">204;
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> }
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> }
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">}

在前后端分离的开发模式下<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>团队协作也面临一些挑战<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>由于前后端职责划分更加明确<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>团队成员需要更加清晰地了解自己的工作边界和与其他成员的协作方式<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>如果职责边界不明确<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>可能会出现前后端在数据校验<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>接口定义等方面的不一致<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>导致开发进度受阻<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>为了解决这个问题<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>团队需要在项目开始前<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>明确前后端的职责边界<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>一般来说<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>后端负责数据的存储<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>业务逻辑的处理以及数据的校验<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>确保数据的准确性和完整性<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>前端则负责用户界面的展示和交互逻辑的实现<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>同时对用户输入的数据进行格式提示和初步的校验<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>但不承担数据的核心校验职责<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>团队可以通过制定详细的接口文档和开发规范<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>明确前后端之间的数据交互格式<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>接口的使用方法等<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>减少沟通成本<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>提高协作效率<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

前后端分离架构还带来了学习成本的挑战<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>对于前端开发人员来说<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>需要掌握更多的技术<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>如 Node.js<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>现代前端框架<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>>React<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>Vue<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>Angular 等<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>以及相关的工具和库<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>对于后端开发人员<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>也需要了解一些前端的基本知识<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>以便更好地与前端协作<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>为了降低学习成本<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>可以通过组织内部培训来提升团队成员的技术能力<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>邀请公司内部的技术专家或者外部的讲师<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>针对前后端分离架构中的关键技术和开发流程进行培训<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>帮助团队成员快速掌握相关知识和技能<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>也可以引入全栈工程师来缓解团队在技术转型过程中的压力<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>全栈工程师具备前后端开发的能力<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>能够在前后端之间起到桥梁的作用<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>帮助解决开发过程中遇到的技术难题<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>同时也可以带动团队成员学习新的技术<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>促进团队的技术提升 <span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

总结

从 LAMP 到前后端分离<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>无疑是 Web 开发领域一次具有深远意义的重要演进<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这一转变不仅体现了技术的发展和进步<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>更是从根本理念上<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>实现了从单纯 “功能实现” 到追求 “高效协作” 的深刻变革 <span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

解耦作为前后端分离架构的核心价值之一<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>具有不可忽视的重要性<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>在 LAMP 架构中<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>前后端代码紧密耦合<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>如同交织在一起的乱麻<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>牵一发而动全身<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这给开发和维护带来了极大的困扰<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>而前后端分离后<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>前端和后端的技术栈实现了独立发展<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>前端能够专注于打造更加优质的用户界面<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>运用各种先进的前端技术和框架<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>不断提升用户体验<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>后端则可以全身心投入到业务逻辑的优化和数据处理中<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>选择最适合的技术和架构<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>提高系统的性能和稳定性<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这种解耦的方式<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>使得前后端能够根据自身的发展需求进行灵活调整和升级<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>有效降低了系统的复杂度<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>提高了系统的可维护性和可扩展性 <span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

前后端分离模式极大地提高了开发效率<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>在传统的 LAMP 架构下<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>前后端的开发相互依赖<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>一个环节的延迟或变更可能会导致整个项目进度的受阻<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>而在前后端分离的模式下<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>前后端团队可以并行开发<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>前端团队可以根据 Mock 数据或 API 文档进行独立开发<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>后端团队也能专注于接口的实现和业务逻辑的处理<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这样一来<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>大大减少了前后端之间的等待时间和沟通成本<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>提高了整体的开发效率<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>使得项目能够更快地迭代和上线<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>更好地满足市场的需求 <span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

前后端分离架构还为系统的扩展性提供了有力支持<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>随着业务的不断发展和用户需求的日益多样化<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>系统需要不断扩展新的功能和模块<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>在前后端分离的架构下<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>通过微服务化的设计<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>后端可以将不同的业务功能拆分成独立的服务<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>每个服务可以独立部署和扩展<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>这样<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>当系统需要增加新的功能时<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>只需对相应的服务进行扩展<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>而不会影响到其他部分<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>引入 Node.js 中间层等技术<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>能够更好地聚合和处理多个后端接口<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>优化系统的性能和响应速度<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>进一步提升系统的扩展性<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>使其能够更好地应对复杂的业务场景 <span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

展望未来<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>随着 Serverless 和低代码技术的不断发展和普及<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>Web 开发的架构模式有望进一步简化<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>Serverless 架构让开发者无需关注服务器的管理和运维<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>只需专注于业务逻辑的实现<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>大大降低了开发和运维的成本<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>低代码技术则通过可视化的操作和模块组装<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>使得非专业的开发者也能够参与到应用的开发中<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>提高了开发的效率和灵活性<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>然而<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>无论技术如何发展<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>“职责清晰<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>协作高效” 的原则都将始终贯穿于 Web 开发的架构设计中<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>成为指导我们构建更加优秀的 Web 应用的核心准则 <span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

拓展<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>CentOS快速部署LAMP


CentOS 快速部署 LAMP 环境<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>>Linux + Apache + MySQL/MariaDB + PHP<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

以下是为 CentOS 7/8/Stream 系统设计的快速部署步骤<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>全程使用命令行操作<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>适用于生产环境和本地测试<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>


1. 更新系统组件

"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"highlight bash"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"code"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"># 更新系统软件包
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">sudo yum update -y
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"># 安装常用工具"bd bd-beg">"bd-box"bd bd-beg">">可选"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">sudo yum install -y wget vim net-tools

2. 安装 Apache

"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"highlight bash"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"code"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"># 安装 Apache
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">sudo yum install -y httpd
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"># 启动 Apache 并设置开机自启
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">sudo systemctl start httpd
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">sudo systemctl "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"built_in"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">enable httpd
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"># 验证 Apache 状态
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">systemctl status httpd

配置防火墙<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>>若开启<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"highlight bash"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"code"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"># 允许 HTTP/HTTPS 流量
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">sudo firewall-cmd --permanent --add-service=http
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">sudo firewall-cmd --permanent --add-service=https
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">sudo firewall-cmd --reload

3. 安装 MySQL/MariaDB

方案 1<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>安装 MariaDB<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>>推荐<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"highlight bash"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"code"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"># CentOS 默认仓库包含 MariaDB
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">sudo yum install -y mariadb-server mariadb
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"># 启动并设置开机自启
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">sudo systemctl start mariadb
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">sudo systemctl "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"built_in"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">enable mariadb
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"># 运行安全配置脚本
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">sudo mysql_secure_installation

提示<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>按需设置 root 密码<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>移除匿名用户<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>禁止远程 root 登录等<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

方案 2<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>安装 MySQL 8.0<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>>需添加官方仓库<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"highlight bash"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"code"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"># 下载 MySQL Yum 仓库
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">wget https://dev.mysql.com/get/mysql80-community-release-el7-6.noarch.rpm
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"># 安装仓库
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">sudo rpm -ivh mysql80-community-release-el7-6.noarch.rpm
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"># 安装 MySQL
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">sudo yum install -y mysql-community-server
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"># 启动并配置
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">sudo systemctl start mysqld
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">sudo systemctl "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"built_in"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">enable mysqld
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"># 获取临时 root 密码
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">grep "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">'temporary password' /var/log/mysqld.log
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"># 运行安全配置
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">sudo mysql_secure_installation

4. 安装 PHP

安装基础 PHP 版本

"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"highlight bash"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"code"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"># CentOS 7 默认仓库提供 PHP 5.4"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"bd bd-beg">建议升级到新版
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"># 安装 EPEL 和 Remi 仓库"bd bd-beg">"bd-box"bd bd-beg">">PHP 7.4/8.0+"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">sudo yum install -y epel-release
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">sudo yum install -y https://rpms.remirepo.net/enterprise/remi-release-7.rpm
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"># 启用指定 PHP 版本"bd bd-beg">"bd-box"bd bd-beg">">例如 PHP 7.4"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">sudo yum-config-manager --"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"built_in"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">enable remi-php74
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"># 安装 PHP 及扩展
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">sudo yum install -y php php-mysqlnd php-gd php-opcache php-mbstring php-json php-xml

验证 PHP

"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"highlight bash"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"code"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"># 创建测试文件
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"built_in"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">echo "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"<?php phpinfo(); ?>" | sudo "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"built_in"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">tee /var/www/html/info.php
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"># 重启 Apache
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">sudo systemctl restart httpd

访问 http://服务器IP/info.php<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>确认 PHP 信息页显示正常<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>


5. 验证 LAMP 环境

测试数据库连接

创建 PHP 文件测试 MySQL 连接<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>>示例代码<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg><h-char class=bd bd-beg>

"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"highlight php"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"code"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"meta"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"><?php
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"variable"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">$servername = "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"localhost";
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"variable"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">$username = "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"root";
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"variable"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">$password = "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"你的MySQL密码";
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">// 创建连接
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"variable"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">$conn = "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">new "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"title function_ invoke__"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">mysqli("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"variable"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">$servername, "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"variable"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">$username, "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"variable"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">$password);
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">// 检查连接
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">if ("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"variable"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">$conn->connect_error) {
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">die("bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"连接失败: " . "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"variable"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">$conn->connect_error);
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">}
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"keyword"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">echo "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"MySQL 连接成功"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">";
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"meta"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">?>

保存为 /var/www/html/db_test.php<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>访问该页面确认输出结果<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>


6. 可选优化

配置虚拟主机

"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"highlight bash"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"code"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"># 创建网站目录
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">sudo "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"built_in"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">mkdir /var/www/mywebsite
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"comment"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"># 编辑 Apache 配置
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">sudo vim /etc/httpd/conf.d/mywebsite.conf

添加以下内容<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"highlight apache"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"code"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"section"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"><VirtualHost *"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"number"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">:80>
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"attribute"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">ServerAdmin admin@example.com
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"attribute"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">DocumentRoot "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"/var/www/mywebsite"
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"attribute"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">ServerName mywebsite.com
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"attribute"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">ErrorLog "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"/var/log/httpd/mywebsite_error.log"
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"attribute"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">CustomLog "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"/var/log/httpd/mywebsite_access.log" combined
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"section"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"><Directory "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"string"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"/var/www/mywebsite">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"attribute"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">AllowOverride "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"literal"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">All
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"attribute"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">Require "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"literal"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">all granted
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"> "bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"section"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"></Directory>
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"section"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"></VirtualHost>

重启 Apache<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"highlight bash"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"code"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">
"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">"line"bd bd-beg">"bd-box"bd bd-beg">">"bd bd-beg">">sudo systemctl restart httpd

常见问题解决

  1. 访问被拒绝

    • 检查防火墙和 SELinux<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>临时关闭 SELinux setenforce 0<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>或配置规则<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>
    • 确认文件权限<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>sudo chown -R apache:apache /var/www/html<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>
  2. PHP 无法连接 MySQL

    • 确认安装 php-mysqlnd 扩展<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>
    • 检查 MySQL 用户权限<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>GRANT ALL PRIVILEGES ON *.* TO '用户名'@'localhost' IDENTIFIED BY '密码';

总结

通过上述步骤<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>您已完成 LAMP 环境的快速部署<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>后续可<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

  • 将网站文件放入 /var/www/html 或自定义目录<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>
  • 配置 HTTPS<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>>使用 Certbot 获取免费 SSL 证书<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg><h-char class=bd bd-beg>
  • 安装 phpMyAdmin 管理数据库<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>sudo yum install -y phpmyadmin<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>

此架构适合传统 PHP 应用<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>>如 WordPress<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>Joomla<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg><h-char class=bd bd-beg>如需更高性能<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>可考虑替换为 Nginx + PHP-FPM<span class=<h-char class=bd bd-beg>bd-box<h-char class=bd bd-beg>><h-char class=bd bd-beg>