HTTP 域名解析一文吃透:从 DNS 到首包的完整路径(含排查清单)

目标:讲清楚“浏览器输入域名到拿到页面”的解析细节常见坑,给可复制的命令与排查步骤。
读完可以:独立配置记录(A/AAAA/CNAME…)、理解 CDN/CNAME 链、定位 404/证书不匹配/“能 ping 不能开” 等问题。

0. 先把链路说清楚(HTTP 并不负责解析)

  1. 浏览器/客户端调用系统的 Resolver(如 getaddrinfo())发起 DNS 查询
  2. 递归解析器(本地 DNS/公共 DNS)解析域名 → 返回 IP(A/AAAA/CNAME…)
  3. 客户端基于返回的 IP 建立连接:
    • http://:TCP 3 次握手 → 发送 HTTP/1.1 请求(带 Host 头)
    • https://:TCP → TLS 握手(SNI 告诉服务器要哪个证书)→ 发起 HTTP
    • h3://(HTTP/3):QUIC/UDP 443 + TLS 1.3
  4. 服务器返回首包;后续可能走 HTTP/2 多路复用或 HTTP/3 0-RTT

关键词:DNS 只负责域名→IPHost 头决定虚拟主机;SNI 决定 HTTPS 证书;HTTP/3 走 UDP


1. 你要会配的记录类型与场景

类型 作用 场景/注意
A 域名 → IPv4 最常用
AAAA 域名 → IPv6 推荐同时配置,配合 Happy Eyeballs 加快首包
CNAME 别名 → 另一个域名 根域名不可 CNAME;CDN 常用(www 指向 xxx.cdn.com
ALIAS/ANAME 顶级域 CNAME 替代(DNS 提供商扩展) 根域名使用 CDN 时选它
NS 指定权威 DNS 顶级域注册后需要在注册商设置 NS
SOA 授权信息/序列号 运维用
TXT 文本/验证 域名验证、SPF、DKIM
MX 邮件 邮件相关
SRV/CAA 服务定位/证书颁发限制 视业务需要

TTL(生存时间)

  • 变更频繁的记录(灰度/切流)用 300–600s;稳定业务 1–4h
  • TTL 不是“全球传播时间”,而是每级缓存的有效期

2. CDN 与 CNAME 链怎么跑

  • 你的业务域名(如 www.example.com)通常 CNAME 到 CDN 分配的域名(如 abc.cdn.com)。
  • 递归解析器解析 CNAME 继续查下去直到 A/AAAA;CDN 据就近/负载返回边缘 IP(多用 Anycast)。
  • 浏览器连到边缘节点,节点再回源到你服务器(按 CDN 的“源站配置”)。

常见坑

  • 根域名不能设 CNAME → 用 ALIAS/ANAME 或让 CDN 提供“根域方案”。
  • HTTPS 证书:域名接入 CDN 后,CDN 与源站都需要证书(视代理/回源方式)。
  • CNAME 链太长导致解析慢 → 尽量控制在 1–2 跳。

3. 浏览器端优化(能省一次解析算一次)

  • DNS 预解析
    <link rel="dns-prefetch" href="//static.example.com">
    
  • 预连接(更激进,会建 TCP/TLS):
    <link rel="preconnect" href="https://static.example.com" crossorigin>
    
  • 多域名合并到同证书 + 同 IP:HTTP/2/3 下可减少连接数(注意证书 SAN 覆盖)。

4. 实操:5 步定位“域名打不开/很慢/证书错”

下面命令 macOS/Linux 可用;Windows 可装 dig(BIND)或用 nslookup

4.1 先看解析结果与链路

# 1) 当前递归解析器的查询
dig www.example.com +nocmd +noall +answer

# 2) 看 CNAME 链与 TTL
dig www.example.com +trace

# 3) 指定权威 NS 直接问(排除递归器问题)
dig @ns1.domain-dns.com www.example.com

# 4) 同时看 IPv6
dig AAAA www.example.com

4.2 建连与证书(HTTP/TLS)

# HTTP:带上 Host,排除反代/网关影响
curl -v http://www.example.com/ -H 'Host: www.example.com'

# HTTPS:看 SNI 告诉了谁、证书是否匹配域名
openssl s_client -connect www.example.com:443 -servername www.example.com </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates

4.3 本机 DNS 缓存与 hosts

  • 临时指向灰度机器:编辑 hosts
    • Windows:C:\Windows\System32\drivers\etc\hosts
    • macOS/Linux:/etc/hosts
  • 清缓存
    • Windows:ipconfig /flushdns
    • macOS:sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder
    • systemd:resolvectl flush-cachessystemd-resolve --flush-caches

4.4 递归器与链路

  • 公司/家庭网关可能劫持或无 ECS,换公共 DNS 试试(1.1.1.1 / 8.8.8.8 / 114 / 阿里…)。
  • traceroute/mtr 观察到边缘节点的路由是否绕远。

4.5 常见返回码

  • NXDOMAIN:记录不存在(看看是否拼错/还未生效/解析层级缺 NS)。
  • SERVFAIL:上游出错;权威 DNS 故障/配置有误。
  • REFUSED:拒绝查询;可能未开放外网递归。

5. 系统解析链与优先级(理解“能 ping 不能开”)

  • 客户端先走 系统解析器/etc/nsswitch.conf 决定顺序),再访问 /etc/hostsresolv.conf 指定的递归器(很多系统是本地 127.0.0.53 的 stub,再转发出去)。
  • 浏览器拿到 多个 A/AAAA 会并发连(Happy Eyeballs),优先最快的;所以“能 ping 不能开”常是 TCP/443 被拦证书/SNI 错,不是 DNS 问题。

6. 业务侧配置建议

  1. 分环境的子域名api.dev.example.comapi.stg…api…;不同 TTL。
  2. 灰度/回滚:提前把备用机器加入记录池(低权重/备用 CNAME),切流只改权重或指向。
  3. IPv6 提前打通:同时配 AAAA,确认负载/防火墙放行 443/80/UDP 443。
  4. DNSSEC(可选):高安全场景开启,避免投毒(注意链路完整性与维护成本)。
  5. 监控:定时 dig +trace、首包时延、解析可用性;报警包含 权威 NS 状态。

7. 典型问题与速解

现象 可能原因 快速定位 解决
刚改记录,外网还指向旧 IP TTL 未过期/上游缓存 dig 看 TTL;换公共 DNS 交叉验证 等 TTL、降 TTL 再变更
只能打开 http://https:// 报证书错 SNI 对不上/证书未覆盖域名 openssl s_client -servername 重新签发证书或修 SNI/反代配置
根域接 CDN 失败 根域不能 CNAME dig 看类型 ALIAS/ANAME 或让 CDN 提供根域方案
海外很慢 Anycast/BGP/回源地域不合适 mtr、CDN 控制台 切 CDN 线路或设回源就近
IPv6 打不开 只配 AAAA 未开放 443/QUIC curl -6 -vnmap -6 放通防火墙/监听 IPv6

8. 一键小脚本(Linux/macOS)

# dnscheck.sh  用法:./dnscheck.sh www.example.com
set -e
domain="$1"
echo "== dig answer =="
dig +nocmd +noall +answer "$domain" || true
echo
echo "== trace =="
dig +trace "$domain" | sed -n '1,60p'
echo
echo "== v4/v6 =="
dig A "$domain" +short; dig AAAA "$domain" +short
echo
echo "== HTTPS cert (SNI) =="
openssl s_client -connect "$domain:443" -servername "$domain" < /dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates || echo "no tls"

9. 代码示例:在应用里正确“解析并建连”

Node.js:dns.lookup(尊重系统策略) vs dns.resolve4/6(直接查)

// npm run node index.js
const dns = require('dns').promises;
const net = require('net');

(async () => {
  const host = 'www.example.com';

  // 1) 系统策略(含 /etc/hosts、v4/v6 优先级、Happy Eyeballs)
  const addr = await dns.lookup(host, { all: true });
  console.log('lookup(all):', addr);

  // 2) 直接查权威结果(不走系统优先级)
  const [a4, a6] = await Promise.allSettled([dns.resolve4(host), dns.resolve6(host)]);
  console.log('resolve4:', a4.status === 'fulfilled' ? a4.value : []);
  console.log('resolve6:', a6.status === 'fulfilled' ? a6.value : []);

  // 3) 简单建连测试
  const ip = (addr[0] || {}).address;
  if (ip) {
    const s = net.createConnection(80, ip, () => {
      console.log('tcp connected to', ip);
      s.end();
    });
    s.setTimeout(3000, () => { s.destroy(); console.error('timeout'); });
  }
})();

Python:socket.getaddrinfo(系统解析)

# python3 demo.py
import socket
host = "www.example.com"
infos = socket.getaddrinfo(host, 80, type=socket.SOCK_STREAM)
print("getaddrinfo:", infos[:3])  # 只打印前几个

生产里尽量用 系统解析lookup/getaddrinfo),以遵循公司内网 DNS/hosts/缓存策略。


10. 备案/内外网双线/分裂视图(Split-Horizon)

  • 内外网返回不同 IP(同一域名):常见于企业内网、K8s 集群 DNS、专线接入。
  • 排查时要明确:你现在连的是哪个递归器/etc/resolv.conf/网络配置),并分别在内外网测 dig

11. Checklist(上线前最后确认)

  • A 与 AAAA 都可用;HTTP/3 需要 UDP 443
  • CDN CNAME 链长度 ≤2;根域使用 ALIAS/ANAME
  • 证书覆盖全部域名(含 www/根域),SNI 配置正确
  • TTL 计划妥当:变更期 300s,稳定后 ≥3600s
  • 监控:解析可用性、首包时延、证书到期告警
  • 文档化:权威 NS、变更流程、回滚方案

结语

域名解析不是“神秘的黑盒”。只要牢记 “DNS 把名字变成 IP,HTTP/HTTPS 再承担传输” 这条主线,加上上面的命令组合拳配置策略,你就能把 80% 的解析相关问题在几分钟内定位清楚、在几小时内无损回滚。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐