Nodejs项目中使用CDN

首先了解一下CDN原理。 在没有使用CDN时,请求大致经过以下步骤:

  1. 客户端得到资源网址

  2. 请求本地DNS服务器(如电信DNS服务器)解析域名

  3. 经顶级DNS服务器将解析请求转由服务端DNS服务器处理 (如阿里云云解析)

  4. 服务端(阿里云云解析)解析到具体IP返回

  5. 客户端得到IP,发送资源请求

使用CDN后,步骤变为

  1. 客户端得到资源网址

  2. 请求本地DNS服务器(如电信DNS服务器)解析域名

  3. 经顶级DNS服务器将解析请求转由服务端DNS服务器处理 (如阿里云云解析)

  4. 服务端DNS服务器根据客户端IP返回与其较近的CDN节点IP

  5. 客户端得到IP,发送资源请求

  6. CDN节点收到请求,如果资源缓存存在且未过期,返回资源。如果没有资源缓存或者已过期,则访问源站点(CDN服务商处配置的源站信息,如七牛可配置为其对象存储空间)请求资源并缓存,而后返回资源

使用七牛存储空间融合CDN的步骤

  1. 添加对象存储空间

  2. 点击“融合CDN加速域名”

  3. 填写加速域名:cdn.abc.com,填写备案号

  4. 创建

  5. 等待一天后,会给出CNAME

  6. 到阿里云云解析后台添加一条解析CNAME记录,把cdn解析到七牛给出的CNAME

  7. 在七牛对象存储空间里上传一张图片,可以通过 cdn.abc.com/efg.jpg访问到图片。

  8. 可以ping cdn.abc.com,会看到解析到的ip对应域名为CDN节点

当然,不使用七牛CDN的情况下,设置CDN很容易,但是我们的需要七牛的存储空间,这样需要解决更多的问题。页面里的资源网址默认为当前域名下的网址,而我们只是使用七牛存储资源,而其他请求仍然不希望发送到七牛。因此需要在页面里使用资源的绝对路径。实际情况变成:页面域名为www.abc.com,图片链接则为 cdn.abc.com/images/xxx.jpg,而在由于可能存在不同的环境,所以,会出现在stage环境图片链接为 cdn.stage.abc.com/images/xxx.jpg,在产品环境则为 cdn.abc.com/images/xxx.jpg。这就要求一种相对智能的部署过程,能够把地址自动改为对应环境的CDN地址。

gulp-cdnizer是一个修改.html/.js/.css文件中的链接地址的gulp插件。你通过类似如下配置,自动根据环境修改链接地址:

gulp.task('cdnizer', function () {
  return merge(
    gulp.src(['.tmp/public/js/**/*.js'])
      .pipe(plugins.cdnizer({
        defaultCDNBase: gulpConfig.cdn[environment],
        allowRev: true,
        allowMin: true,
        matchers: [
          {
            pattern: /(<img\s.*?src=\\["'])(.+?)(\\["'].*?>)/gi,
            fallback: true
          }
        ],
        files: gulpConfig.cdnizer.files
      }))
      .pipe(gulp.dest('.tmp/public/js')),
    gulp.src(['.tmp/public/styles/**/*.css'])
      .pipe(plugins.cdnizer({
        defaultCDNBase: gulpConfig.cdn[environment],
        allowRev: true,
        allowMin: true,
        files: gulpConfig.cdnizer.files
      }))
      .pipe(gulp.dest('.tmp/public/styles')),
    gulp.src(['.tmp/public/index.html'])
      .pipe(plugins.cdnizer({
        defaultCDNBase: gulpConfig.cdn[environment],
        allowRev: true,
        allowMin: true,
        files: gulpConfig.cdnizer.files
      }))
      .pipe(gulp.dest('.tmp/public'))
    );
});

如果你使用七牛的对象存储空间,你可以使用gulp-qiniu在部署的时候自动上传文件到七牛:

gulp.task('cdn', function (done) {
  gulp.src(gulpConfig.tmp.distAssets)
    .pipe(plugins.qiniu({
      accessKey: gulpConfig.qiniu.accessKey,
      secretKey: gulpConfig.qiniu.secretKey,
      bucket: gulpConfig.qiniu.bucket[environment],
      private: false
    }, {
      dir: 'console',
      versioning: false,
      concurrent: 10
    }));

  setTimeout(done, 10000); // 前面加return不work,所以在这儿等着
});

这样站点支持CDN的改造工作就算基本完成了。