# 把服务放到正确的域名后面

原文: https://yishto.com/learn/delivery/deployment-dns-gateways-and-cdn/

作者: [Yishto](https://yishto.com/about/)

沿域名、证书、代理、源站与缓存逐层检查资料站交付，明确多语言缓存、私有响应和托管产品的边界。

首次发布: 2026-11-10
内容更新: 2026-11-10

资料站准备把预览服务放到公开域名后面，同时提供中文和英文课程页面。浏览器需要先找到服务，再验证连接，最后取得正确版本的内容。域名已经解析成功，只能证明其中一段链路成立，不能说明证书、路由、源站与缓存都正确。

案例使用 `/learn/` 作为公开课程入口，`/account/` 作为个人页面。前者允许共享缓存，并随语言变化；后者含用户数据，不进入共享缓存。路径是教学契约，没有真实账号或线上测试结果。

## 先画出请求经过的每一层

一次访问可以经过 DNS 解析、TLS 终止、反向代理或网关、应用源站和存储。CDN 可能在源站之前直接返回已有内容。每一层都可能产生自己的错误，所以诊断时应记录目标域名、协议、路径、响应状态、部署版本与请求标识。

源站负责生成或提供内容，反向代理负责转发，负载均衡器负责在多个后端间选择，网关可能集中实施身份与流量规则。某个平台会把这些功能合并，但职责仍值得分开检查。代理返回的 502 与应用返回的 404 对应不同调查方向。

先确定哪些路由是静态资源，哪些需要应用执行，哪些访问私有对象。把路径契约写出来：`/learn/` 应返回课程索引，缺失课程返回真实 404，个人页面需要身份验证。不能让所有未知路径都返回首页而仍声称路由正确。

## DNS 只解决名称定位

A 记录把名称映射到 IPv4 地址，AAAA 对应 IPv6，CNAME 指向另一名称。DNS 不包含 URL 路径，也不会自动为服务配置 TLS 证书。把域名指向新机器之后，机器上仍需要服务监听、路由规则和与域名匹配的证书。

解析器与客户端可能缓存记录，TTL 指示缓存的有效时间。更新并非全球同时发生，已有连接也不会因为 DNS 变化立即切换。切换前可安排更低 TTL，但应考虑旧记录仍按原 TTL 缓存，以及平台对记录的限制。

核查应区分权威记录、当前解析器看到的记录与浏览器最终使用的地址。只查看管理控制台的值，无法说明用户链路已经取到新值。若开放 IPv6，也要核对 AAAA 指向的服务，否则不同网络可能进入不同版本。

## TLS 与代理需要明确可信入口

TLS 保护传输过程，并通过证书等机制验证连接端点。它不能证明应用返回的内容没有被污染，也不为业务请求授予权限。证书需要覆盖访问的主机名，续期与到期监控也属于持续交付责任。

若 TLS 在代理处终止，应决定代理到源站是否仍加密，以及源站如何限制可达入口。原始 HTTP 客户端可以提交转发头，应用不能无条件信任 `X-Forwarded-For` 或 `X-Forwarded-Proto`。只有经过受信任代理并按明确规则重写的值，才适合作为客户端信息的依据。

代理与后端超时需要一起设计。后端处理很久，代理先超时，客户端可能重试，引发重复任务。长预览任务可以返回任务 ID 再查询，避免靠任意增加超时解决。负载均衡健康检查还要考虑新实例预热、旧连接排空与所有后端失效时的行为。

## 缓存键必须覆盖响应差异

缓存把某次响应保存下来，让后续匹配的请求复用。判断能否共享前，应问内容是否随用户、语言、权限、查询参数或部署版本变化。把中文和英文请求放进同一个键，可能让先到的语言覆盖另一种；把个人页面放进去，则可能暴露数据。

本例只为公开课程路径与两种明确语言构造键。private 参数表示已经由可信应用逻辑判定为私有，真实系统不能靠用户自己传一个布尔值选择隐私等级。

```python
def cache_key(path, language, private=False):
    if private:
        return None
    if language not in {"zh", "en"}:
        raise ValueError("unsupported language")
    return path + "|" + language
assert cache_key("/learn/", "zh") != cache_key("/learn/", "en")
assert cache_key("/account/", "zh", private=True) is None
print(cache_key("/learn/", "zh"))
```

实际输出是 `/learn/|zh`。断言确认中英文键不同，个人页返回 `None` 表示不进入这份共享缓存。未知语言会抛出 `ValueError`。函数没有解析 HTTP 请求，也没有设置真实 CDN 规则，返回 None 本身不会禁止外部缓存。

实施时还要配置响应缓存策略，并核对代理、浏览器与 CDN 各自的行为。静态文件可用带内容指纹的 URL 区分版本；经常更新的课程索引需要刷新或较短有效期。缓存键太粗会返回错误内容，太细则降低复用并增加存储，两者都应通过请求样本检查。

## 选择托管方式时核对产品边界

VPS 给开发者较多运行控制，同时带来补丁、进程管理、备份与入口维护。静态托管适合预构建页面，但动态认证与后台任务需要其他运行能力。托管平台减少一部分运维步骤，仍要检查构建条件、运行时、权限、地域、配额和恢复方法。

Cloudflare Workers 的静态资源功能可以结合 Worker 路由与资源绑定提供内容；R2 是对象存储，不能把存储对象等同于应用运行环境。公开桶、私有读取与域名接入也应分别配置。选择时先列需要执行的逻辑，再判断产品是否覆盖它。

现有 ModelScope Studio 仓库说明的是基于 Gradio 的组件库，不能据此推断任意静态网站都有生产托管能力或 SLA。若考虑相关托管服务，应继续核对当前平台文档与账号可用条件。缺少证据时，把结论限制为组件能力，而不编造上线流程。

切换计划还应保留上一版产物与路由配置，说明恢复动作怎样作用于每层。源站回到旧版本之后，CDN 可能继续返回新版本缓存；反过来，清空缓存也不能修复错误源站。恢复验收应重新请求关键页面，核对内容和状态，再宣布切换结束。

## 练习：按链路验证一次版本切换

准备一张验证表，覆盖 HTTP 到 HTTPS、主域名与备用域名、中文与英文、缺失路由、个人页面和静态资源。重定向需核对状态码与 Location。对于非 GET 方法，应根据契约选择适当的重定向语义，不能假定所有客户端对 301 都保持方法。

验收时，同一公开路径的两种语言不能串缓存；个人内容不被共享复用；缺失路径有正确状态；证书主机名匹配；静态文件和页面能核对部署版本。模拟旧 DNS、过期缓存和后端不可用，记录在哪一层观察到问题、怎样恢复。真实发布时再用外部请求复核这张表，本文离线函数只证明键的局部规则。

## 资料来源与延伸阅读

- [Domain names and DNS](https://developer.mozilla.org/en-US/docs/Learn_web_development/Howto/Web_mechanics/What_is_a_domain_name)
- [TLS 1.3 — RFC 8446](https://www.rfc-editor.org/rfc/rfc8446.html)
- [NGINX beginner's guide](https://nginx.org/en/docs/beginners_guide.html)
- [Workers static assets — Configuration and bindings](https://developers.cloudflare.com/workers/static-assets/binding/)
- [Object storage concepts](https://developers.cloudflare.com/r2/)
- [ModelScope Studio components and official examples](https://github.com/modelscope/modelscope-studio)

资料核验：2026-11-10。教学示例不代表线上实测。

## 相关文章

- [从网址到页面：一次请求经过哪些边界](https://yishto.com/learn/computing/web-request-journey/)
- [多语言页面怎样兼顾 SEO 和加载体验](https://yishto.com/learn/web-interface/localization-and-web-performance/)
