在您的网站上添加和利用 CDN

Avatar of David Attard
David Attard

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 $200 免费信用额度!

如果您在 Web 开发领域工作了一段时间,您就会知道 Web 需要速度。事实很简单:速度很重要,更快被认为更好。

提高性能的一个“简单方法”是使用CDN。我们在 CSS-Tricks 中已经多次讨论过这个问题。它很简单,因为您不需要重写代码库或手动编辑内容,但这是我们许多人可能会忽略的性能领域,因为,嗯,托管、服务器和 cPanel,哦,我的天哪!

值得庆幸的是,集成 CDN 的过程并不一定很困难。理想情况下,您将配置好这些内容,然后像 Google PageSpeed 这样的工具会以高性能分数的形式发出欢呼声,这反过来又会带来更好的搜索引擎排名、更高的收入、您的加薪等等……您明白了。

这篇文章将介绍为自定义 Web 应用程序设置 CDN 的过程,以及一些我们可以用来充分利用我们工作的技巧。正如我所说,它并不一定很困难,所以让我们深入研究,让 Web 更快吧!

值得注意的是,对于使用 WordPress 等 CMS 的用户来说,设置 CDN 可能比我们这里介绍的要简单,因为插件可以帮助完成这项工作。我们将假设并非所有人都享有这种便利(向 Web 应用程序致敬!),并以更传统的方式进行操作。

等等,你讲到 CDN 的时候我就听不懂了

我们回顾一下 CDN 的基本概念以及它们的使用目的,从这里开始。

CDN 的工作原理是,从您的网站服务器获取静态资源并将它们缓存在其服务器上。当浏览器请求访问您的网站时,静态内容将通过 CDN 提供,而不是通过您的网站提供。这样做速度更快,因为 CDN 服务器在全球范围内分布,并充当代理,确定哪个服务器物理上最靠近您的访问者,从而以更快的、更便捷的网络提供内容。因此,它的全称是:内容分发网络。

内容分发网络在全球范围内分布,以优化静态资源的交付

那么,浏览器如何知道从 CDN 获取资源而不是从您的服务器获取资源呢?您的静态资源的 URL 将被替换为指向 CDN 服务器,而不是指向您自己网站的 URL。

例如,假设我们希望 CDN 被配置为子域。对于 CSS-Tricks,它可能是类似于 cdn.css-tricks.com 的内容,这将是我们所有资产的相对 URL 基础。

简而言之,我们网站上像这样的资产的 URL

https://css-tricks.org.cn/image.jpg 
https://css-tricks.org.cn/style.css 
https://css-tricks.org.cn/script.js

…将变成

http://cdn.css-tricks.com/image.jpg 
http://cdn.css-tricks.com/style.css 
http://cdn.css-tricks.com/script.js

浏览器向您的 CDN 发送请求,而不是向您的服务器发送请求,从而减轻服务器的负载,并最终使您的整个网站更快。

等等,一个网站用两台服务器?

是的,在某种程度上,但这并不意味着您要管理两台服务器。

我们实际上是在讨论使用 CDN 作为虚拟层,它位于您的服务器和用户的浏览器之间。该虚拟层监听浏览器向您的服务器发送的请求,并乐于代表服务器使用缓存的资产进行响应。

在某些情况下,您可能直接将资产上传到 CDN,并将所有负担从您的服务器上卸下。我们将在本文中讨论的是一个流程,其中 CDN 从您的服务器获取资产并预先缓存它们,因此不需要上传到不同的服务器并管理多个位置。

如何在自定义应用程序上实现 CDN

两个最广泛使用的 CDN 服务是 Amazon AWSMaxCDN,当然还有许多其他服务可用。我们将重点关注 MaxCDN 作为设置方法的示例。

步骤 1:选择 CDN 并注册您的网站

一旦您决定 CDN 是您 Web 应用程序的最佳选择,您就需要注册一个帐户。有很多很多选项可供选择,而不是权衡每个选项的优缺点(这可能是一个很好的未来文章),这里列出了一些入门选项。

注册帐户时,一个常见的步骤是设置一个**拉取区域**或**分发**。拉取区域或分发由 CDN 作为您日常支持文件的存储桶使用。它将自动从您指定的某个位置拉取数据,以响应对该文件的第一个请求。这些文件将通过您选择的 CDN 的子域或您选择的指向 CDN 的自定义域(子域)提供给最终用户。存储桶中的数据将在可自定义的时间段后从服务器自动清除。

步骤 2:创建您的 CDN URL

您的 CDN URL 是所有资产在设置完成后将指向的 URL。一个好的经验法则是使用一个 URL 名称,该名称易于在您的数据库中对所有现有 URL 进行搜索和替换。

与任何其他子域一样,这需要在您的主机 DNS 设置中作为 CNAME 记录进行设置。

主机用于配置 CNAME 记录的典型 cPanel 屏幕

步骤 3:将您的资产指向 CDN

让我们看一下创建 CDN URL 变量的方法,以及如何使用它来帮助以编程方式将 URL 添加到我们的静态资源之前。我们之所以要这样做,是因为 (1) 它可以减少我们在标记中犯错的可能性,以及 (2) 如果我们需要更改 URL,它更容易维护 URL。

我们将通过定义一个全局 CDN 变量来做到这一点,然后将此变量添加到我们的静态资源 URL 之前。我们在 PHP 和 JavaScript 级别都定义了此变量,以便我们在将来使用它时具有更大的灵活性。如果我们决定放弃 CDN,它也使我们更容易操作,因为我们只需用一个简单的 / 替换变量,即可恢复到原始服务器的相对路径。

请注意,以下示例旨在说明示例,而不是字面上的用法。您的实际用法可能有所不同。

<?php
define('cdnURL', 'http://cdn.css-tricks.com/');
?>
<html>
    <head>
        <title>Hello World!</>
        <script type='text/javascript'>
            /* Let’s define a javascript global for using the CDN inside scripts */
            var cdnURL = '<?php echo cdnURL ?>';
        </script>
        
        <link rel='stylesheet' href='<?php echo cdnURL ?>css/style.css' />	
    </head>
    <body>
        <img src='<?php echo cdnURL ?>img/logo.png' />
        <button>Submit</button>
        <script type='text/javascript' src='<?php echo cdnURL ?>js/main.js'></script>
    </body>
</html>

或者,在 JavaScript 中完成

(function() {
    var preloadImage = document.createElement('img');
    preloadImage.src = cdnURL + 'img/logo.png';
})();

这确实需要您作为开发人员稍微改变一下思维方式。每个静态资源都需要在前面加上 cdnURL 变量。

同样的想法也适用于您的 CSS。例如,我们还可以设置一个全局 CDN 变量,并使用 CSS 预处理器(如 LESS)将其添加到我们的 CSS 资源之前

@cdnURL: 'http://cdn.css-tricks.com/';
button {
  background-image: url('@{cdnURL}img/button.png');
  &:hover {
    background-image: url('@{cdnURL}img/button_hover.png');
  }
}

…或者 Sass 也是一样的

$cdnURL: 'http://cdn.css-tricks.com/';

button {
  background-image: url('#{$cdnURL}img/button.png');
  &:hover {
    background-image: url('#{$cdnURL}img/button_hover.png');
  }
}

最棒的是,您可以通过将 cdnURL 设置为 / 来关闭 CDN,这将重新创建您所有的相对 URL。这还有一个好处,那就是如果您想切换 CDN URL,您只需要更改 cdnURL 即可。

这确实是设置 CDN 的三个步骤,将 CDN 链接到您的服务器,然后将您现有的资产指向它,以便 CDN 可以在被请求时提供这些内容。

让我们谈谈一些高级设置

设置 CDN 并没有那么可怕,对吧?现在我们已经克服了主要的障碍,我们可以玩一些高级设置,优化我们的资产服务方式。

生存时间 (TTL)

CDN 通常会为资产设置一个生存时间 (TTL)。这是一种告诉 CDN 在多久(以秒为单位)内应该将资产视为过期的花哨方式。在那之后,它会在服务器上再次查找“新鲜”的副本。

TTL 越长,该资产的“版本”将在 CDN 中停留的时间越长,并继续被提供。TTL 越短,它就越频繁地放弃存储的资产“版本”,并返回到原始服务器以查找更新的版本。

MaxCDN 缓存设置屏幕,用于设置 TTL 过期时间

使资产无效

TTL 的双刃剑是,您可以在服务器上更新资产,但更改不会反映在您的网站上,直到 TTL 到期,CDN 才会再次访问服务器以查找新的副本。

我们可以通过使资产无效来克服这个问题。这里的诀窍是在更新时更改文件名。如果文件名更改,CDN 不会知道任何差别,并将新命名的文件视为一个全新的资产,而不是对现有资产的更新。

换句话说,这个:http://cdn.css-tricks.com/image100.jpg

…将被重命名为类似于:http://cdn.css-tricks.com/image101.jpg

再见旧版本,你好新版本!

利用 TTL 进行版本控制

嘿,所以如果 CDN 保留了资产的一个版本,并且我们的服务器上有一个它还没有获取的最新副本,那么我们实际上有两个相同资产的迭代。我们可以用它来创建一种“版本控制”形式,在服务器上更新资产并不意味着我们自动丢失它们,并且可以在需要时恢复到过去的副本。

真正复杂的做法是在每次更改时重命名所有资源,就像我们在使资产无效时所做的那样。但是,从维护角度来看,即使我们必须为此创建一个变量(就像我们为cdnURL所做的那样),这也是过分的。我们将进行一些作弊,因为这就是我们在一个以技巧为基础的博客上运作的方式。

我们将从将静态资产放置到它们自己的文件夹中开始,这样一来:http://cdn.css-tricks.com/image.jpg

…变成了这样:http://cdn.css-tricks.com/img100/image.jpg

为了使文件失效并强制 CDN 提供最新版本,我们将修改子目录路径,如下所示:http://cdn.css-tricks.com/img101/image.jpg

看到区别了吗?文件名保持不变,但它现在似乎位于服务器上的目录中。同样,CDN 不会知道任何差别,并将此视为一个全新的文件。我们刚刚创建了一个伪版本控制形式,它直接发生在文件夹中!

但是等等,我们可以做得更好。

每次更新时都更改文件夹上的数字仍然是一个繁琐的过程,并且是维护我们网站的另一个步骤。我们可以做的是对网站的.htaccess文件进行一些小的更改,以便为我们完成繁重的工作。

我们将通过从同一个文件夹中提供所有资产来欺骗 CDN,但让它看起来像是从版本化的文件夹中提供,这要归功于一些重写规则。

<IfModule mod_rewrite.c>
	RewriteEngine On
	RewriteBase /
	RewriteRule ^ver-[0-9]+.[0-9]+.[0-9]+(.*)$ $1 [L,NC]
	RewriteCond %{REQUEST_FILENAME} !-d
	RewriteCond %{REQUEST_FILENAME} !-f
	RewriteRule ^(.*)$ index.php?/$1 [QSA,L]
</IfModule>

哈!现在我们的服务器正在 URL 中伪造版本号,同时从服务器上最初上传的同一个路径提供我们的示例image.jpg资产。

按需使所有资产无效

最后一件要做的事情是将我们的版本控制技巧整合到我们的 HTML 标记中,这样一来,只要我们想要完全使资产失效,CDN 就会刷新所有资产。

我们将设置一个配置文件,在其中定义一个版本号的变量,将该变量导入到我们的资产 URL 结构中,然后在每次想要在整个范围内推送资产刷新时更改版本号。

下面是它在 PHP 配置文件中可能的样子

VERSION
1.0.0

Configure::load('cdn');
define('VERSION', file_get_contents(APP.DS."Config".DS."VERSION"));
define('CDN', Configure::read('CDN.path').VERSION.'/'); /* the trailing slash is important */

下面是它在 LESS 配置文件中可能的样子

@VERSION: '1.0.0';

@import 'cdn';
@import 'version';
@CDNURL: '@{CDN}@{VERSION}/';
 
button {
    background-image: url('@{CDNURL}img/button.png');
    &:hover {
        background-image: url('@{CDNURL}img/button_hover.png');
    }
}

如您所见,您还可以选择将 CDN 变量用作文件、环境变量或任何最适合您的方式。原则基本相同,所有这些都会实现将 CDN URL(和版本号)合并到我们所有外部资源中的预期最终结果。

CDN,FTW!

希望这能消除设置 CDN 的恐惧。它当然看起来是一项艰巨的任务,并且绝对存在一些高级设置,可能会让你迷失在细节中。初始设置是我们大多数人需要的,并且在性能和用户体验方面,以及其他众多方面(双关语)带来了巨大的好处。

事实是,如果您使用流行的 CMS(如 WordPress)管理网站上的内容,那么它会变得更加简单,因为有大量的插件可以进一步简化流程。

即使我们没有插件的优势,设置 CDN 仍然非常简单,即使是那些最不了解托管的人也是如此。设置是最大的障碍,我们已经将其分解为三个基本步骤。其他的事情就顺理成章了。