一、架构设计

(一) 分层架构

Web 应用主要采用层级架构的设计,整体可以分为三层:

  • 表现层(Presentation Layer):处理用户交互,使用 HTML/CSS/JavaScript 构建界面。
  • 业务逻辑层(Business Layer):执行核心业务规则,如数据验证和事务处理。
  • 数据访问层(Data Layer):负责数据库操作,常用 ORM 框架实现。

层次架构的优点为:

  • 分离关注点:每一层都有其特定的职责,这有助于开发人员专注于各自的任务。
  • 可维护性:由于层与层之间的耦合度低,修改一层不会影响其他层,这使得维护和升级变得更加容易。
  • 可扩展性:可以根据需要独立扩展每一层,以应对不同的性能和功能需求。
  • 可测试性:每一层可以独立进行单元测试,这有助于提高代码质量和发现潜在问题。

层次架构的局限为:

  • 性能损耗:跨层调用可能产生性能损耗(约 5%-10% 请求延迟)。
  • 污水池反模式:请求简单的穿过几个层,每层里面基本没有或很少做业务逻辑。这种层次隔离失效的情况,容易导致业务修改时出现遗漏和不一致的问题。解决办法是层次开发,即允许部分数据的处理直达核心层,而不用层层穿越。

(二) 前后端分离

在分层架构中,表现层属于前端处理,业务逻辑层和数据访问层属于后端处理。通过‌前后端分离的模式,解耦前端与后端开发,从而提升开发效率、系统可维护性和用户体验‌。

  • 前端:主要由 HTML、CSS 和 JavaScript 构成。通常使用前端框架(React、Vue.js、Angular)进行开发。
  • 后端:可以选择不同的编程语言和框架来实现,如 Node.js、Django(Python)、Spring Boot(Java)等。
  • 通信:
    • 数据交互:多数场景使用 JSON,高性能场景使用 Protobuf
    • 接口风格:Restful 风格
    • 跨域请求:CORS 跨域访问

二、前端技术

前端表现层通常有 MVC/MVP/MVVM 三种架构:

模式 MVC MVP MVVP
核心组件 - 模型(Model):数据存储与业务逻辑
- 视图(View):用户界面展示
- 控制器(Controller):处理用户输入,协调模型与视图
- 模型(Model):数据存储与业务逻辑
- 视图(View):用户界面交互接口
- 呈现器(Presenter):处理逻辑,控制视图更新
- 模型(Model):数据存储与业务逻辑
- 视图(View):绑定数据的 UI
- 视图模型(ViewModel):数据转换与双向绑定
数据流 单向为主(存在双向例外) 双向(通过 Presenter 中介) 双向(自动绑定)
数据交互 视图可直接调用控制器,也可能直接访问模型 视图通过接口与呈现器通信,不直接访问模型 视图通过数据绑定与视图模型交互,无直接逻辑调用
耦合度 高(View 与 Controller 耦合) 低(通过接口解耦) 最低(数据绑定解耦)
  1. MVC 数据流

    • 理论上是 单向数据流(用户→View→Controller→Model→View),实际上常出现 Controller 直接操作 View 的反模式
      graph LR
      A[用户] -->| 操作 | B(View)
      B -->| 事件通知 | C(Controller)
      C -->| 更新 | D(Model)
      D -->| 推送新数据 | B
      C -.->| 可能直接操作 | B
  2. MVP 数据流

    • 双向数据流,呈现器是视图与模型之间的唯一中介
      graph LR
      A[用户] -->| 操作 | B(View 接口)
      B -->| 委托事件 | C(Presenter)
      C -->| 调用 | D(Model)
      D -->| 返回数据 | C
      C -->| 通过接口 | B
      B -.->| 查询数据 | C
  3. MVVM 数据流

    • 双向数据流,通过绑定视图和视图模型实现自动同步,无需显式调用接口完成视图更新
      graph LR
      A[用户] -->| 操作 | B(View)
      B -->| 自动绑定 | C(ViewModel)
      C -->| 更新数据 | D(Model)
      D -->| 数据变更 | C
      C -->| 数据驱动 | B

三、后端技术

1. RESTful

REST 全称是 Representational State Transfer,中文意思是 表述性状态转移。如果一个架构符合 REST 的约束条件和原则(如下表所示),我们就称之为 RESTful 风格。

概念 解释
资源标识 资源是任何有被引用必要的事物,包括实体和抽象概念。使用 URI 作为资源唯一标识,可看作资源地址或名称。
操作接口 使用标准 HTTP 方法访问资源。GET 表示获取资源;POST 表示创建资源;PUT 表示全局更新资源;DELETE 表示删除资源;PATCH 表示局部更新资源。
资源表述 客户端获取资源表述,通常采用 json、xml 等格式描述资源。
资源链接 利用超媒体概念,在表述格式中添加相关操作的链接,驱动客户端的状态转移。
无状态 服务端不保存客户端状态,客户端的每次请求需要包含完整的上下文信息。

2. CORS 跨域访问

为了保护用户的安全和隐私,浏览器默认使用 同源策略,即要求协议、域名、端口三者完全相同,才能正常访问。

解决跨域问题,常见的方案有:

  • CORS(跨域资源共享):在服务器端设置响应头部,允许指定的域名访问资源。
  • JSONP(JSON with Padding):通过在页面中动态添加 \元素,利用 script 标签的跨域特性来获取数据。
  • 代理服务器:在服务器端设置一个代理服务器,将请求代理转发到目标服务器,绕过浏览器的同源策略。
对比项 CORS JSONP 代理服务器
支持方法 所有方法 GET 方法 所有方法
安全性
兼容性 现代浏览器 老旧浏览器 所有浏览器
适用场景 API 接口、单点登录 第三方数据加载 无法修改服务端时

CORS 通过在 HTTP(s)请求和响应中使用特定的头部字段来实现跨域资源共享,具体来说,CORS 分为两种类型的请求处理方式:简单请求和预检请求。

  • 简单请求:对于某些简单的 HTTP 请求(如 GET、POST 请求,且不包含自定义头部),浏览器会直接发送请求,并在响应中检查 CORS 头部。
  • 预检请求:对于复杂请求(如使用 PUT、DELETE 方法,或包含自定义头部),浏览器会首先发送一个 OPTIONS 请求,称为预检请求(Preflight Request),以确定服务器是否允许实际请求。如果预检请求通过,浏览器会继续发送实际请求。

服务器可以通过设置响应头部来细粒度配置 CORS:

响应头字段 作用 示例
Access-Control-Allow-Origin 允许的源(* 表示允许所有) *
Access-Control-Allow-Methods 允许的 HTTP 方法 GET, POST, PUT
Access-Control-Allow-Headers 允许的自定义请求头 Authorization, Content-Type
Access-Control-Max-Age 预检请求缓存时间(秒) 3600
Access-Control-Allow-Credentials 是否允许携带 Cookie(需配合 withCredentials) true

四、性能

1. 负载均衡

负载均衡(Load Balance)是将网络流量或计算任务动态分配到多台服务器 / 计算节点的技术,旨在优化资源利用、提升系统吞吐量并保障服务高可用性。其优势在于:

  • 消除单点故障,提升系统容错能力
  • 实现水平扩展,突破单机性能瓶颈
  • 降低响应延迟,改善用户体验

负载均衡的实现方案可以分软硬件两大类:

  • 硬件负载均衡:使用专用硬件设备(如 F5 BIG-IP),性能卓越但成本高昂
  • 软件负载均衡:通过软件实现,灵活经济,是市场主流技术
对比维度 F5 BIG-IP DNS 负载均衡 LVS Nginx HAProxy Istio 服务网格
原理 专用硬件处理全协议流量,集成 SSL 卸载与安全防护 域名解析返回多个 IP 地址,客户端自动轮询访问 Linux 内核 IPVS 模块实现四层转发 反向代理拦截 HTTP 请求,通过 upstream 模块分配流量 基于状态机的连接处理,精细化 TCP 会话管理 Envoy 代理 Sidecar 模式拦截流量,控制平面动态下发路由规则
性能 百万级 QPS,支持全协议 无额外延迟(受 TTL 缓存限制) 四层转发性能接近硬件 万级 QPS 高并发 TCP 吞吐 依赖 Envoy 代理性能
稳定性 冗余设计,金融级可靠性 中(依赖 DNS 冗余设计) 热备方案支持高可用 高可用需配合 Keepalived 动态健康检查 基于 K8s 自动容错
配置难度 低(GUI 界面) 低(多 A 记录配置) 高(需内核调优) 低(配置文件) 中(策略复杂) 高(YAML 声明式配置)
成本 高昂(20 万 +) 低(仅 DNS 服务费用) 免费(开源) 免费(开源) 免费(开源) 中等(运维复杂度高)
支持层级 四层 / 七层 四层 四层 七层为主 四层 / 七层 七层
典型场景 金融核心交易系统 全局流量分发(如 CDN) 大规模 TCP 流量分发 Web 服务器 /API 网关 数据库集群负载 微服务流量治理

负载均衡算法 可分为静态算法和动态算法:

  1. 静态分配策略
    • 轮询算法:依次分配请求,适合服务器性能均等场景
    • 加权轮询:根据服务器处理能力设置权重比例(如 4 核服务器权重为 2 核的 2 倍)
    • 源地址哈希:基于客户端 IP 固定分配服务器,保持会话连续性
  2. 动态调整策略
    • 最少连接数:优先选择当前连接数最少的节点,适用于长连接服务(如 FTP)
    • 响应时间优先:通过 ICMP 探测选择延迟最低节点,改善实时交互体验
    • 自适应混合算法:结合 CPU 负载、内存使用率等指标动态计算权重
graph TD
    A[新请求] --> B{算法选择}
    B -->| 常规请求 | C[轮询 / 加权轮询]
    B -->| 会话保持需求 | D[源地址哈希]
    B -->| 实时性要求高 | E[响应时间优先]
    B -->| 复杂业务场景 | F[自适应混合算法]

2. 读写分离

读写分离的实现策略:

  1. 数据库层:MySQL 主从复制(延迟 <100ms)
    • 原理:MySQL 主从复制通过二进制日志(binlog)实现数据同步。主库将事务写入 binlog,从库通过 IO 线程拉取日志,并由 SQL 线程重放日志以应用数据变更。
  2. 中间件:MyCAT/ShardingSphere 实现自动路由
    • MyCAT:按哈希、范围等规则将数据分散到多个库表,通过 schema.xml 定义逻辑表与物理节点映射。配置 balance=1 实现读请求随机分发到从库,写请求强制路由至主库。
    • ShardingSphere:通过 Sharding-JDBC 在 JDBC 层拦截 SQL,自动改写为分片语句。
  3. 缓存层:Redis 集群 + 读写分离(读性能提升 10 倍)
    • 原理:采用一致性哈希将 Key 分配到 16384 个槽位,每个节点管理部分槽位。通过 READONLY 命令标记从节点为只读,代理层将 80% 读请求分发至从节点。

读写分离的数据一致性保障:

  1. 半同步复制:主库提交事务前需至少一个从库确认接收 binlog 并写入中继日志,主库收到从库 ACK 后再正式提交事务。
  2. 数据库中间件:所有读写走中间件,记录写操作的 key,主从同步时间窗口内,读请求路由到主库,窗口期过了再路由到从库。
  3. 缓存记录:写操作时记录 key 到 cache,并设置超时时间,再修改主库。读操作时先查 cache,命中则路由到主库,未命中则路由到从库。

五、安全性

1. JWT 认证

JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在各方之间以 JSON 对象形式安全传递信息。其核心特性是 无状态性,即服务器无需存储用户会话信息,仅通过令牌本身的签名和内容验证用户身份。

JWT 由三部分构成,用点号(.)分隔:Header.Payload.Signature

  • Header:包含令牌类型和签名算法。
  • Payload:存储用户身份信息和声明。通过 Base64 编码,但未加密,不可存放密码等敏感信息。
  • Signature:通过加密算法对 Base64(Header).Base64(Payload)和密钥(secret_key)计算生成,用于防篡改。

服务端验证步骤为:

  1. 解析 JWT,提取 Header 和 Payload。
  2. 用相同算法和密钥重新生成签名,比对客户端传来的 Signature,若一致则合法。
  3. 对合法令牌验证声明(如检查 exp 是否过期、iss 是否合法)是否有效,若有效则通过。

2. CSRF 攻击

CSRF(Cross-Site Request Forgery,跨站请求伪造)是一种利用用户已认证身份发起非授权操作的攻击方式。其核心在于浏览器自动携带用户凭证(如 Cookie),而服务器无法区分请求是否由用户主动发起。

CSRF 攻击流程:

  1. 用户登录受信任网站(如网银),服务器返回身份凭证(Cookie) 。
  2. 用户访问恶意网站 B,该网站嵌入指向网站 A 的恶意请求(如转账 API)。
  3. 浏览器自动携带网站 A 的 Cookie,向网站 A 发送请求,服务器误认为是合法操作并执行。

CSRF 防御措施:

  1. 验证 CSRF Token:服务器生成随机 Token 嵌入表单或请求头,验证请求是否携带有效 Token。
  2. 设置 SameSite Cookie 属性:Strict 模式完全禁止跨域携带 Cookie,Lax 模式仅允许安全方法(如 GET)且导航类请求携带。
  3. 检查 Referer/Origin 头部:验证请求来源域名,拦截非信任域名的请求。
  4. 双重认证机制:敏感操作(如转账)需二次验证,如短信验证码、人脸识别。