DNS预解析设置方法

DNS预解析是一种通过提前解析域名来减少网络延迟的技术,当用户可能访问某个域名下的资源时,浏览器可以在实际请求发出前就完成DNS查询,从而消除DNS解析带来的等待时间,显著提升后续资源加载的速度。

DNS预解析的工作原理

浏览器在加载页面时,如果遇到一个需要从其他域名获取的资源(例如一个托管在CDN上的图片或脚本),它必须首先将该域名解析为IP地址。这个过程称为DNS解析,通常需要几十到几百毫秒。DNS预解析的核心思想是“预测”用户下一步可能访问哪些域名,并提前在后台发起DNS查询。

其工作流程大致如下:

  1. 浏览器解析HTML时,发现带有特定关系的链接标签。
  2. 浏览器不会阻塞当前页面的渲染,而是在后台发起一个低优先级的DNS查询请求。
  3. 当用户真正触发对目标域名的请求时(例如点击链接或加载资源),DNS解析结果很可能已经缓存,从而实现了“零等待”解析。

如何设置DNS预解析

设置DNS预解析主要通过在HTML文档的<head>部分添加带有rel="dns-prefetch"属性的<link>标签来实现。

基本语法

html 复制代码
<link rel="dns-prefetch" href="https://cdn.example.com">

这个标签告诉浏览器:“我很快可能需要从cdn.example.com这个域名加载资源,请提前解析它的DNS。”

自动解析与手动解析

现代浏览器通常会对当前页面中出现的所有链接(<a>标签的href属性)进行自动的DNS预解析。然而,对于通过JavaScript动态添加的资源、CSS背景图引用的域名,或者隐藏在代码深处的API端点,浏览器可能无法自动发现。这时就需要手动添加预解析提示。

示例:预解析动态加载资源的域名
假设你的页面会通过JavaScript动态加载一个来自第三方分析服务的脚本。

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>我的页面</title>
    <!-- 手动预解析第三方域名 -->
    <link rel="dns-prefetch" href="https://analytics.thirdparty.com">
    <link rel="dns-prefetch" href="https://cdn.widgets.com">
</head>
<body>
    <!-- 页面内容 -->
    <a href="https://shop.example.com">去商城</a> <!-- 此链接会被浏览器自动预解析 -->

    <script>
        // 稍后动态加载的资源
        setTimeout(() => {
            const script = document.createElement('script');
            script.src = 'https://analytics.thirdparty.com/tracker.js';
            document.head.appendChild(script);
        }, 3000);

        // 动态加载一个小组件
        function loadWidget() {
            const link = document.createElement('link');
            link.rel = 'stylesheet';
            link.href = 'https://cdn.widgets.com/style.css';
            document.head.appendChild(link);
        }
        document.getElementById('widgetBtn').addEventListener('click', loadWidget);
    </script>
</body>
</html>

在这个例子中,我们手动预解析了analytics.thirdparty.comcdn.widgets.com,确保即使用户交互后才触发加载,DNS解析也已经提前完成。

预解析与预连接、预加载的配合

DNS预解析常与其他资源提示(Resource Hints)配合使用,形成性能优化组合拳。

  • dns-prefetch:仅解析DNS。
  • preconnect:在DNS解析的基础上,进一步建立TCP连接并进行TLS握手(对于HTTPS)。这比仅DNS预解析开销更大,但收益也更高,适用于你非常确定即将发起关键请求的域名。
  • preload:用于强制浏览器提前加载并缓存某个特定资源(如字体、关键CSS)。

组合使用示例:
对于一个至关重要的、来自CDN的Web字体,可以这样设置:

html 复制代码
<head>
    <!-- 第一步:提前解析DNS -->
    <link rel="dns-prefetch" href="https://fonts.cdn.com">
    <!-- 第二步:提前建立连接(包含DNS、TCP、TLS) -->
    <link rel="preconnect" href="https://fonts.cdn.com" crossorigin>
    <!-- 第三步:提前加载字体文件本身 -->
    <link rel="preload" as="font" href="https://fonts.cdn.com/myfont.woff2" type="font/woff2" crossorigin>
</head>

注意:为外部资源(跨域)使用preconnectpreload时,通常需要添加crossorigin属性,即使该资源CORS策略是匿名的。

最佳实践与注意事项

1. 识别需要预解析的域名

使用Chrome DevTools的“Network”面板或Lighthouse等审计工具,检查页面加载的所有资源。重点关注:

  • 关键的第三方资源(分析、字体、CDN库)。
  • 用户交互后可能访问的域名(如下一页面的域名、弹窗内容域名)。
  • CSS中background-image引用的外部域名。

2. 控制预解析的数量

DNS预解析虽然成本较低,但并非无成本。浏览器对并发DNS查询有限制,过度添加预解析标签可能挤占其他重要资源的解析机会。只预解析最关键的几个域名。

3. HTTPS页面的特殊处理

对于HTTPS页面中需要预连接的HTTP资源,或者反过来,浏览器出于安全考虑可能不会执行。尽量保持协议一致。对于现代网站,应主要关注HTTPS域名的预解析。

4. 动态注入预解析标签

对于单页应用(SPA),可以根据路由变化动态注入下一视图可能需要的资源预解析提示。

javascript 复制代码
// 假设在进入“用户仪表盘”路由时,需要预解析仪表盘专用API和图表的域名
function onEnterDashboardRoute() {
    const preconnectLinks = [
        'https://api.dashboard.example.com',
        'https://charts.cdn.example.com'
    ];

    preconnectLinks.forEach(domain => {
        const link = document.createElement('link');
        link.rel = 'dns-prefetch';
        link.href = domain;
        document.head.appendChild(link);

        // 也可以同时建立预连接,如果资源非常关键
        const preconnectLink = document.createElement('link');
        preconnectLink.rel = 'preconnect';
        preconnectLink.href = domain;
        preconnectLink.crossOrigin = 'anonymous';
        document.head.appendChild(preconnectLink);
    });
}

5. 使用HTTP头进行预解析

除了HTML标签,还可以通过HTTP响应头Link来发送预解析指令。这对于无法直接修改HTML的静态资源或API响应特别有用。

复制代码
Link: <https://cdn.otherdomain.com>; rel=dns-prefetch

服务器可以在响应中返回这个头部,指示浏览器预解析指定的域名。

效果验证与监控

添加DNS预解析后,需要通过工具验证其效果。

在Chrome DevTools中验证:

  1. 打开DevTools,进入 Network 面板。
  2. 刷新页面,观察网络请求瀑布图。
  3. 找到来自你预解析域名的资源(例如一个脚本或图片)。
  4. 查看该请求的“Timing”标签。如果预解析成功,你会看到“DNS Lookup”阶段的时间极短(显示为0ms或几毫秒),或者旁边有一个“dns-prefetch”的提示。

使用Lighthouse审计:
运行Lighthouse性能审计,在“Opportunities”部分,它可能会建议“Preconnect to required origins”。你可以根据这个建议来添加dns-prefetchpreconnect

浏览器支持与降级策略

dns-prefetch得到了所有现代浏览器的广泛支持。对于不支持此特性的旧版浏览器,添加对应的标签是安全的,它会被简单地忽略,不会产生任何副作用。因此,这是一种典型的渐进增强优化手段。

与HTTP/2服务器推送的区分

需要注意的是,DNS预解析与HTTP/2的服务器推送(Server Push)是截然不同的技术。DNS预解析发生在浏览器端,仅解析域名。而服务器推送是服务器在响应一个请求时,“主动”将其他资源推送给浏览器。两者可以互补使用,但解决的问题不同。