从浏览器输入 URL 到页面显示:DNS、Nginx、后端与 CDN 全链路解析

从浏览器输入 URL 到页面显示:DNS、Nginx、后端与 CDN 全链路解析

  • 前言
  • [1. 一次请求的整体地图](#1. 一次请求的整体地图)
  • [2. DNS:把域名变成可访问地址](#2. DNS:把域名变成可访问地址)
    • [2.1 为什么浏览器不能只拿域名建立连接](#2.1 为什么浏览器不能只拿域名建立连接)
    • [2.2 DNS 查询如何逐层找到答案](#2.2 DNS 查询如何逐层找到答案)
  • [3. TCP 与 HTTPS:先连通,再安全传输](#3. TCP 与 HTTPS:先连通,再安全传输)
    • [3.1 TCP 三次握手解决什么问题](#3.1 TCP 三次握手解决什么问题)
    • [3.2 TLS 为 HTTP 加上一层保护](#3.2 TLS 为 HTTP 加上一层保护)
  • [4. Nginx:统一入口与反向代理](#4. Nginx:统一入口与反向代理)
    • [4.1 为什么这叫反向代理](#4.1 为什么这叫反向代理)
    • [4.2 Nginx 在请求链路中还会做什么](#4.2 Nginx 在请求链路中还会做什么)
  • [5. 服务器集群与负载均衡](#5. 服务器集群与负载均衡)
    • [5.1 反向代理与负载均衡不是一回事](#5.1 反向代理与负载均衡不是一回事)
  • [6. NestJS:真正处理业务请求的地方](#6. NestJS:真正处理业务请求的地方)
    • [6.1 两个典型 API 请求](#6.1 两个典型 API 请求)
  • [7. MySQL 与 Redis:一个保存事实,一个加速访问](#7. MySQL 与 Redis:一个保存事实,一个加速访问)
    • [7.1 以文章详情为例理解缓存](#7.1 以文章详情为例理解缓存)
  • [8. 静态资源为何应走独立链路](#8. 静态资源为何应走独立链路)
  • [9. OSS:让大体积对象有合适的存放位置](#9. OSS:让大体积对象有合适的存放位置)
    • [9.1 上传与访问的常见分工](#9.1 上传与访问的常见分工)
  • [10. CDN:把静态资源更快地送到用户附近](#10. CDN:把静态资源更快地送到用户附近)
    • [10.1 缓存命中与回源](#10.1 缓存命中与回源)
  • [11. 两条完整请求链路](#11. 两条完整请求链路)
    • [11.1 动态 API 请求:需要业务判断与数据访问](#11.1 动态 API 请求:需要业务判断与数据访问)
    • [11.2 静态资源请求:优先由 CDN 与对象存储服务](#11.2 静态资源请求:优先由 CDN 与对象存储服务)
  • 总结

前言

刚开始接触 Web 开发时,一个接口看起来往往很直接:浏览器调用 GET /api/posts/42,后端返回一段 JSON。但把域名放进地址栏后,请求并不是瞬间抵达某个 Controller。它会先找到可连接的地址,建立安全连接,经过接入层转发,再由业务服务读取数据;如果页面还包含图片、脚本和字体,这些资源通常走的是另一条更适合分发的链路。

理解这条路径的价值,不在于背下每个网络术语,而在于建立一张清晰的"分工图":谁负责定位、谁负责接入、谁负责业务、谁负责保存数据、谁负责分发大体积资源。排查"页面打不开""接口很慢""图片加载慢"时,也就知道该从哪一层入手。

可以把一次访问理解为一次协作:DNS 负责找到入口,Nginx 负责接待并分流,NestJS 负责办理业务,MySQL 和 Redis 提供数据,OSS 与 CDN 负责高效送达静态资源。

1. 一次请求的整体地图

先看最常见的动态请求主干。这里的"服务器/接入层 IP"不一定是某台 NestJS 机器的地址,也可能是负载均衡器或 CDN 的入口地址;这是现代部署中非常常见的设计。

text 复制代码
浏览器输入域名
    ↓
DNS 解析
    ↓
获得服务器/接入层 IP
    ↓
TCP 三次握手
    ↓
HTTPS 场景下进行 TLS 握手
    ↓
Nginx / 负载均衡层
    ↓
NestJS 后端服务器集群
    ↓
MySQL / Redis
    ↓
返回数据

以访问 https://api.example.com/api/posts/42 为例:浏览器先通过 DNS 找到 api.example.com 对应的可访问地址;连接建立后,请求到达 Nginx;Nginx 选择一台健康的 NestJS 实例;该实例读取文章数据,必要时优先从 Redis 获取缓存,未命中再查询 MySQL,最后将 JSON 沿原路返回浏览器。

层次 主要职责 初学者最应记住的一点
DNS 域名解析为可连接地址 域名是便于记忆的名称,网络连接需要地址
TCP / TLS 建立可靠、安全的传输通道 先连通,再安全地传数据
Nginx 统一接入、转发、分流 它通常不处理具体业务规则
NestJS API 与业务编排 Controller、Service、鉴权通常在这里发生
MySQL / Redis 数据持久化与高速访问 两者解决的问题不同,常常配合使用
OSS / CDN 存储与加速静态资源 大资源不应挤进业务接口链路

2. DNS:把域名变成可访问地址

2.1 为什么浏览器不能只拿域名建立连接

人更擅长记住 www.example.com 这样的名称,网络设备建立连接时却需要知道目标在哪里。IP 地址就是网络中的寻址信息。**DNS(Domain Name System,域名系统)**承担的工作,正是将便于记忆的域名转换为可用于连接的 IP 地址,或先转换为另一个域名记录再继续查询。

这个机制还带来一个实际好处:应用可以迁移机器、扩容接入层或切换服务商,而用户继续访问同一个域名即可。变更的是 DNS 记录及后端部署,用户使用的入口名称不必改变。

2.2 DNS 查询如何逐层找到答案

一次查询不一定每次都要从最上层开始。浏览器、操作系统和递归 DNS 都可能保存过往结果,并且记录带有 TTL(缓存有效期)。缓存仍有效时,查询可以很快结束;缓存失效或没有记录时,才需要继续向下查找。

text 复制代码
浏览器 / 操作系统缓存
↓
递归 DNS
↓
根 DNS
↓
顶级域 DNS
↓
权威 DNS
↓
IP 地址

其中各角色的关系可以这样理解:

  • 本地缓存:浏览器和操作系统会暂存近期结果,减少重复查询。
  • 递归 DNS:通常由网络运营商、公共 DNS 服务或企业网络提供。它替用户完成后续查询,并会缓存答案。
  • 根 DNS:知道顶级域 DNS 的入口在哪里,不直接保存所有具体域名的最终地址。
  • 顶级域 DNS :管理如 .com.cn 这类顶级域的委派信息,告诉查询方某个域名应去找哪组权威 DNS。
  • 权威 DNS:保存某个域名实际配置的 DNS 记录,是最终答案的权威来源。

例如查询 api.example.com 时,递归 DNS 可能先向根 DNS 询问 .com 的去向,再向 .com 的顶级域 DNS 询问 example.com 的权威 DNS,最后从权威 DNS 获取 api.example.comAAAAA 记录。A 通常对应 IPv4,AAAA 通常对应 IPv6。实际服务也可能通过 CNAME 指向另一个域名,递归 DNS 会继续完成解析。

DNS 的职责是"找到可访问的入口",并不等同于承诺"必然返回物理距离最近的一台业务机器"。是否就近、如何调度,取决于 DNS 配置、CDN、负载均衡和网络策略等多种因素。

常见现象 更可能优先检查的位置
刚改域名解析,部分用户仍访问旧地址 TTL 与各级缓存是否尚未过期
域名无法解析 权威 DNS 记录、域名委派、拼写与记录类型
同一域名解析出多个地址 可能用于高可用、流量分配或多入口部署

3. TCP 与 HTTPS:先连通,再安全传输

拿到 IP 后,浏览器才知道该向哪里发起连接。对于传统的 HTTPS 网站,可以先把连接过程压缩成下面三步:

text 复制代码
DNS
↓
TCP 三次握手
↓
TLS 握手
↓
HTTP 请求

3.1 TCP 三次握手解决什么问题

TCP 是面向连接的传输协议。所谓三次握手,可以先理解为客户端和服务端在正式传数据之前,彼此确认"我能发到你""我能收到你""我们准备好了"。这个过程帮助双方建立一条可靠的连接状态,之后 HTTP 请求和响应才能稳定地在这条连接上收发。

不必在初学阶段纠结序列号、窗口大小等实现细节。工程上更有用的认识是:DNS 成功只说明找到了地址;TCP 成功才说明目标端口可以建立连接。 如果握手失败,可能是服务未监听、端口被防火墙拦截,或者网络路由不可达。

3.2 TLS 为 HTTP 加上一层保护

当地址以 https:// 开头时,TCP 建立后通常还要进行 TLS 握手。浏览器会校验证书,并与服务端协商后续通信所需的加密参数。握手完成后,HTTP 请求内容才在加密通道中传输。

TLS 的关键收益是三件事:验证访问对象的身份、保护传输内容不被轻易窥视、降低内容在传输中被篡改的风险。证书过期、域名与证书不匹配、接入层未正确配置证书,都会让浏览器在 HTTP 请求前就提示安全问题。

阶段 解决的问题 失败时常见表现
DNS 解析 域名对应什么地址 域名找不到、解析超时
TCP 握手 能否与目标端口建立连接 连接超时、连接被拒绝
TLS 握手 能否建立可信的加密通道 证书告警、HTTPS 连接失败
HTTP 传输 请求能否被正确处理 4xx5xx 或响应慢

4. Nginx:统一入口与反向代理

浏览器通常不直接访问某台具体的 NestJS 实例。因为业务服务可能有多台,会扩缩容、发布和故障切换;把它们的真实地址直接暴露给客户端,管理和安全都会变得困难。实践中,外部请求经常先到 Nginx 或云负载均衡等接入层,再由接入层将请求转发给内部业务服务。

text 复制代码
用户
↓
Nginx
↓
NestJS Server

4.1 为什么这叫反向代理

代理的核心是"代替一方发起或接收请求"。正向代理靠近客户端:客户端把访问外部站点的请求先交给代理,由代理代为访问目标。它主要服务于客户端侧的访问控制、网络出口等场景。

反向代理靠近服务端:用户只知道一个统一入口,反向代理在后面代表服务端接收请求,并将请求交给合适的业务服务。用户无需知道 NestJS 实例的数量、地址和变化。

类型 代理站在哪一侧 客户端通常是否知道真实目标
正向代理 客户端一侧 通常知道要访问的外部站点
反向代理 服务端一侧 通常只需要知道统一服务入口

4.2 Nginx 在请求链路中还会做什么

Nginx 常见职责包括 TLS 证书终止、域名与路径路由、请求转发、压缩、访问日志、限流,以及静态资源直接响应。例如 /api/ 前缀转发给 NestJS,而 /assets/ 则可以由 Nginx 或 CDN 直接服务。这种划分避免所有资源请求都进入业务框架。

下面是便于理解的配置片段:

nginx 复制代码
server {
    listen 443 ssl;
    server_name api.example.com;

    location /api/ {
        proxy_pass http://nestjs_cluster;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

这段配置表达的重点是:收到 api.example.com/api/ 请求后,Nginx 将其转发给名为 nestjs_cluster 的后端集群。真实项目还会补充超时、跨域、限流和日志等配置,但"统一入口再转发"的主线不变。

5. 服务器集群与负载均衡

单台后端服务容易遇到两个问题:访问量上来后性能有限;机器故障或发布重启时,服务可能整体不可用。因此,大型网站通常会让多台机器运行同一套 NestJS 程序,形成后端集群。对外仍保持一个域名和一个接入入口,对内则把请求分配给多个实例。

text 复制代码
            → NestJS A
用户 → Nginx → NestJS B
            → NestJS C
            → NestJS D

5.1 反向代理与负载均衡不是一回事

二者经常都由 Nginx 承担,因此容易混淆。反向代理回答的是"请求由接入层代为转给后端";负载均衡进一步回答"这一次具体转给哪一台后端"。

text 复制代码
反向代理:请求转发给真正后端
负载均衡:决定具体转发给哪一台后端
能力 核心问题 例子
反向代理 请求是否经过统一入口转发 /api/ 转给 NestJS 服务
负载均衡 多个后端中选择哪一个 本次转给 A,下次转给 B
健康检查 某个实例是否还能接收流量 B 异常后暂时不再分配请求

常见分配策略包括:

  • 轮询:按顺序依次分配,适合实例规格和请求耗时比较接近的场景。
  • 加权轮询:性能更高的实例获得更高权重,从而承担更多流量。
  • 最少连接:优先选择当前连接数较少的实例,对请求耗时差异较大的场景更有帮助。

健康检查是可用性的另一层保障。接入层会通过探测接口、连接状态或云平台健康检查判断实例是否异常;某个实例无法正常服务时,会被暂时摘除,恢复健康后再加入流量分配。需要注意,负载均衡并不能自动让业务变正确:登录状态、临时数据和幂等等问题,仍需在应用设计中处理。

6. NestJS:真正处理业务请求的地方

Nginx 关心的是"把请求交给谁",NestJS 关心的是"这个请求该怎么处理"。NestJS 是 Node.js 生态中的后端框架,常用于构建结构化 API。它通常负责接收请求、校验参数、登录鉴权、执行业务逻辑、调用数据层,最后返回 JSON。

text 复制代码
Nginx:决定请求交给谁
NestJS:决定这个请求具体怎么处理

6.1 两个典型 API 请求

登录接口通常是一个写操作。NestJS 接收到 POST /api/login 后,先校验账号和密码是否完整,再查询用户信息、比对凭证,成功后生成访问令牌或建立会话,最后返回登录结果。文章详情接口则通常是读操作:GET /api/posts/:id 先从路径中读取 id,校验格式并查询文章,再返回相应 JSON。

text 复制代码
POST /api/login

GET /api/posts/:id

下面用简化的 NestJS Controller 展示路由入口。重点不是记住装饰器,而是看清每个 HTTP 请求会被路由到对应的业务方法。

typescript 复制代码
@Controller('api')
export class AppController {
  constructor(private readonly authService: AuthService) {}

  @Post('login')
  async login(@Body() dto: LoginDto) {
    return this.authService.login(dto);
  }

  @Get('posts/:id')
  async getPost(@Param('id') id: string) {
    return this.postService.findById(id);
  }
}

一次请求在 NestJS 中常见的执行顺序是:路由匹配到 Controller,Pipe 完成参数转换与校验,Guard 判断是否有权限,Service 组织业务规则并调用 Repository 或其他服务,最终由 Controller 返回结果。出现错误时,Exception Filter 可以把异常转换成统一的 HTTP 响应格式。

NestJS 不应承担所有工作。连接接入、静态资源分发和海量二进制对象传输交给更擅长的组件,业务服务才能保持专注、易扩展。

7. MySQL 与 Redis:一个保存事实,一个加速访问

NestJS 处理业务时通常需要数据支撑。MySQL 是关系型数据库,适合保存需要长期保留、结构明确、可关联查询的业务事实,例如:

  • 用户
  • 文章
  • 评论
  • 点赞
  • 收藏

Redis 是内存型键值存储,读写很快,常用于缓存、Session、验证码、热点数据和计数器。它的价值在于减少重复计算和重复查询,快速应对高频访问;但它通常不能替代 MySQL 作为关键业务事实的长期唯一来源。

text 复制代码
Nginx
↓
NestJS
↓
MySQL / Redis

7.1 以文章详情为例理解缓存

当大量用户同时浏览热门文章时,如果每次都查询 MySQL,数据库会承担大量相同读取。一个常见做法是:NestJS 先查询 Redis;若缓存命中,直接返回;若未命中,再查询 MySQL,把结果写入 Redis 并设置合适过期时间。

text 复制代码
GET /api/posts/42
↓
NestJS 查询 Redis
├─ 命中:直接返回文章详情
└─ 未命中:查询 MySQL → 写入 Redis → 返回文章详情
存储 更适合保存 设计时要注意
MySQL 用户、订单、文章等核心业务数据 表结构、索引、事务与一致性
Redis 缓存、会话、验证码、计数器 过期策略、缓存更新与内存容量

缓存并非"加上就一定更快"。数据更新后如何让缓存同步失效,是常见难点。例如文章编辑成功后,可以删除对应缓存,让下一次读取重新从 MySQL 构建缓存。对于点赞数这样的热点计数器,也要结合业务容忍度设计异步汇总和最终一致性策略。

8. 静态资源为何应走独立链路

页面中的图片、CSS、JavaScript、字体和视频等都属于静态资源。它们的共同特点是:内容通常不会因每个用户而频繁变化,且单个对象可能很大、请求数量也多。若每一次请求都进入 NestJS 的 Controller、鉴权和业务逻辑,会消耗本不必要的计算资源,也让业务服务承担了不擅长的传输工作。

更合理的分工是:动态 API 走 Nginx 与 NestJS;静态资源由 Nginx 直接响应,或进一步交给 OSS 与 CDN。浏览器仍然只是在请求一个 URL,但服务端内部走的是更合适的通道。

请求类型 示例 通常处理者
动态请求 GET /api/posts/42 Nginx → NestJS → 数据存储
静态资源 GET /assets/logo.svg CDN / Nginx / OSS
上传请求 POST /api/uploads NestJS 负责鉴权与生成上传凭证,对象存储承接内容

这种拆分还会让扩容更精准:接口压力高时扩 NestJS;图片访问量高时提高 CDN 覆盖和缓存策略;大体积对象存储增长时扩展 OSS 容量,而不必让所有压力都落在同一类机器上。

9. OSS:让大体积对象有合适的存放位置

图片、附件、音视频等二进制对象通常不直接存进 MySQL 的业务表。对象存储服务,如 OSS、S3、COS,更适合保存这类内容:容量扩展方便,可通过 URL 访问,也能和 CDN 更自然地协同。

MySQL 更适合保存与业务相关的元数据,例如对象名称、访问 URL、大小、媒体类型、上传者和关联文章。一个概念上的记录可以是:

text 复制代码
filename
URL
size
mimetype
userId
postId

9.1 上传与访问的常见分工

上传时,NestJS 可以先验证用户身份、校验类型和大小限制,再把内容写入对象存储,或签发短时有效的直传凭证让浏览器直接上传。上传完成后,业务服务将 URL 和关联信息写入 MySQL。读取文章详情时,NestJS 返回图片 URL;浏览器随后根据该 URL 从 CDN 或对象存储获取资源实体。

这种设计避免让 MySQL 承担大对象传输,也让数据库备份、查询和迁移更可控。对于私有资源,还可以使用签名 URL 或访问控制策略,避免仅凭一个公开地址就能长期访问。

OSS 的重点是可靠存放对象;MySQL 的重点是保存对象与业务之间的关系。二者不是替代关系,而是分层协作。

10. CDN:把静态资源更快地送到用户附近

CDN(Content Delivery Network,内容分发网络的核心作用是缓存和就近分发静态资源。CDN 在不同地区部署边缘节点,用户请求图片、脚本等资源时,DNS 或 CDN 调度系统会引导请求到合适的节点。若节点已缓存所需内容,就可以直接返回,减少回到源站的距离与压力。

这里的"合适"不只是地理距离,还会综合网络质量、节点健康和调度策略。因此可以把 CDN 理解为提升资源获取效率的分发网络,而不是一个简单的"永远最近节点"承诺。

10.1 缓存命中与回源

当 CDN 节点中已经有当前版本的资源且仍在有效期内,称为缓存命中 ,节点直接响应用户。当节点没有该资源、缓存已过期,或策略要求校验源站内容时,称为需要回源:CDN 向 OSS 或源站请求资源,拿到后按策略缓存,再返回用户。

text 复制代码
用户
↓
CDN
↓
缓存命中 → 直接返回
↓
未命中
↓
OSS / 源站
↓
CDN 缓存
↓
返回用户
概念 含义 对用户与源站的影响
缓存命中 边缘节点已有可用资源 返回更快,源站压力更小
回源 节点从 OSS 或源站获取资源 首次或失效后可能更慢,会增加源站请求
缓存过期 缓存控制时间结束 需要按策略重新校验或获取资源

资源更新时,CDN 缓存策略尤为重要。工程上常用带版本号或内容哈希的 URL,例如 app.8f3a2c.js。内容改变时 URL 同时改变,浏览器与 CDN 可以安全地长时间缓存旧版本,而新版本通过新 URL 获取,减少"用户看到旧资源"的问题。紧急更新时,也可以使用 CDN 刷新或预热能力,但要了解其生效范围与成本。

11. 两条完整请求链路

11.1 动态 API 请求:需要业务判断与数据访问

以用户查看文章详情为例,浏览器访问 https://api.example.com/api/posts/42。DNS 将域名解析为接入层地址;浏览器完成 TCP 和 TLS 握手;Nginx 接收请求并根据负载策略选择一台 NestJS 实例;NestJS 校验参数后先查 Redis,未命中则查询 MySQL,最后组装 JSON 返回。

text 复制代码
浏览器
↓
DNS
↓
TCP / TLS
↓
Nginx
↓
NestJS
↓
MySQL / Redis

这个过程中,每一层都可以独立观测:DNS 看解析结果与 TTL,Nginx 看访问日志和上游耗时,NestJS 看接口日志和错误率,MySQL 看慢查询,Redis 看命中率。这样定位性能问题时,不必笼统地说"后端慢"。

11.2 静态资源请求:优先由 CDN 与对象存储服务

同一篇文章返回的 JSON 中可能包含封面图 URL。浏览器随后请求该图片时,一般不会再进入文章详情的 NestJS 业务流程,而是通过 CDN 获取;节点缓存未命中时,CDN 再向 OSS 或源站回源。

text 复制代码
浏览器
↓
DNS
↓
CDN
↓
OSS / 源站

这两条链路相互配合:动态 API 保证内容和权限正确,静态资源链路保证图片、脚本等高效交付。它们不是谁取代谁,而是在不同类型的请求上各司其职。

总结

从地址栏输入域名到页面呈现内容,是一条由多个组件接力完成的路径。DNS 将好记的名称转换为可访问地址;TCP 与 TLS 让通信通道可靠且安全;Nginx 提供统一入口,并将流量代理、分配给健康的 NestJS 实例;NestJS 承载鉴权、校验和业务规则;MySQL 保存长期业务事实,Redis 缓解热点访问;OSS 存放大体积对象,CDN 通过边缘缓存加速静态资源。掌握这种边界感,比孤立记住某个组件的命令更重要:当请求出现异常或性能下降时,可以顺着链路分层定位,也能在系统增长时有针对性地扩展。

text 复制代码
DNS:域名 → IP
Nginx:代理 + 负载均衡
NestJS:业务逻辑
MySQL:持久化业务数据
Redis:缓存和高速数据
OSS:存对象
CDN:加速静态资源访问
相关推荐
mengge.cloud1 小时前
云计算&服务器基础小白教程
android·linux·运维·服务器·网络·云计算
一路向北finish1 小时前
《Hadoop 高可用集群与 OpenStack Mitaka 控制节点部署全流程实操排坑指南》
大数据·linux·运维·服务器·hadoop·openstack
南棱笑笑生1 小时前
20260826解决在Ubuntu22.04系统下编译RK3572的Buildroot【linux-6.12.69】出现CMake异常的问题
linux·运维·服务器
hh9501 小时前
Agent Plan x DeepSeek Harness:分布式Agent集群调度与负载均衡
运维·分布式·负载均衡·adg·agent plan·adg成都社区
FIT2CLOUD飞致云1 小时前
3分钟通过1Panel搭建安全隔离的DeepSeek Harness
运维·开源·1panel·运维面板
NGINX开源社区1 小时前
使用 F5 NGINX Gateway Fabric 实现 AI 交付标准化
nginx·gateway·fabric
王志来137944730081 小时前
多元场景催生工控服务器机箱差异化需求匀天以柔性适配回应行业挑战
运维·服务器·人工智能·python
小张同学a.2 小时前
OpenStack 私有云实战 2—— Glance 镜像与 Nova 计算服务搭建
linux·运维·服务器·openstack