Nodejs项目中使用CDN
首先了解一下CDN原理。 在没有使用CDN时,请求大致经过以下步骤:
-
客户端得到资源网址
-
请求本地DNS服务器(如电信DNS服务器)解析域名
-
经顶级DNS服务器将解析请求转由服务端DNS服务器处理 (如阿里云云解析)
-
服务端(阿里云云解析)解析到具体IP返回
-
客户端得到IP,发送资源请求
使用CDN后,步骤变为
-
客户端得到资源网址
-
请求本地DNS服务器(如电信DNS服务器)解析域名
-
经顶级DNS服务器将解析请求转由服务端DNS服务器处理 (如阿里云云解析)
-
服务端DNS服务器根据客户端IP返回与其较近的CDN节点IP
-
客户端得到IP,发送资源请求
-
CDN节点收到请求,如果资源缓存存在且未过期,返回资源。如果没有资源缓存或者已过期,则访问源站点(CDN服务商处配置的源站信息,如七牛可配置为其对象存储空间)请求资源并缓存,而后返回资源
使用七牛存储空间融合CDN的步骤
-
添加对象存储空间
-
点击“融合CDN加速域名”
-
填写加速域名:cdn.abc.com,填写备案号
-
创建
-
等待一天后,会给出CNAME
-
到阿里云云解析后台添加一条解析CNAME记录,把cdn解析到七牛给出的CNAME
-
在七牛对象存储空间里上传一张图片,可以通过 cdn.abc.com/efg.jpg访问到图片。
-
可以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的改造工作就算基本完成了。