将网站静态资源全部上传到cdn

2023-01-12 10:16:59 浏览数 (1)

1. 对象存储

对象存储类似云盘,可以将一些小文件存储进去,并暴露出来外链,配合cdn之后访问非常快。我们的目标就是把网站的css、js、图片等其他一些资源上传进去,再通过cdn来加速访问。

这里我使用到的是腾讯云的cos对象存储: https://console.cloud.tencent.com/cos

1.1 新建存储桶

首先新建一个存储桶

选个离自己近的地域,起个名称,先选择公有读私有写。然后一路下一步就行。

1.2 上传文件

点进刚刚建好的存储桶,随便上传一个文件,我传了一个图片

1.3 查看域名

存储桶列表,找到刚刚建好的存储桶,点配置管理,可以看到我们的访问域名

访问域名 文件路径 就可以访问到我们上传到存储桶的资源

可以直接访问测试一下

2. node自动上传

我们可以在存储桶上传我们的js、css之类的文件、不过我们的文件那么多,一个一个上传明显不合理。要你你也不干。

这时候,这些批量又重复的操作应该由我们的node出马,让我们来通过 node来批量上传我们的资源文件

2.1 获取密钥

在密钥管理下可以新建一个密钥,一会要用

2.2 遍历目录

既然要上传所有静态文件,那么就要先拿到所有静态文件的绝对路径。这里我写了个方法文件,可以遍历指定目录,返回一个数组。

注意,遍历目录的方法是异步的,所以这里使用promise,大概一秒足够遍历完所有文件

代码语言:javascript复制
1// node fs模块
2const fs = require("fs");
3// node path模块
4const path = require("path");
5
6// 收集所有的文件路径
7const arr = [];
8const fileDisplay = (filePath) => {
9  //根据文件路径读取文件,返回文件列表
10  return new Promise((resolve) => {
11    fs.readdir(filePath, function (err, files) {
12      if (err) return console.error("Error:(spec)", err);
13      files.forEach((filename) => {
14        //获取当前文件的绝对路径
15        const filedir = path.join(filePath, filename);
16        // fs.stat(path)执行后,会将stats类的实例返回给其回调函数。
17        fs.stat(filedir, (eror, stats) => {
18          if (eror) return console.error("Error:(spec)", err);
19          // 是否是文件
20          const isFile = stats.isFile();
21          // 是否是文件夹
22          const isDir = stats.isDirectory();
23          if (isFile) {
24            // 这块我自己处理了多余的绝对路径,第一个 replace 是替换掉那个路径,第二个是所有满足的直接替换掉
25            arr.push(
26              filedir
27                .replace(
28                  "D:lhstudyjiaoshoujiavuegenerator-lh-vuegeneratorsapp",
29                  ""
30                )
31                .replace(//gim, "/")
32            );
33          }
34          // 如果是文件夹
35          if (isDir) fileDisplay(filedir);
36        });
37      });
38    });
39
40    setTimeout(() => {
41      resolve(arr);
42    }, 1000);
43  });
44};
45module.exports = fileDisplay;
46

2.3 编写上传脚本

脚本思路就是,先把cdn上原来旧的文件清理,然后再将新文件逐一上传。 这里封装了两个方法

代码语言:javascript复制
1const fs = require("fs");
2const path = require("path");
3const COS = require("cos-nodejs-sdk-v5");
4//上面封装的遍历目录方法
5const fileDisplay = require("./fileDispaly");
6//2.1拿到的密钥
7const cos = new COS({
8  SecretId: "xxxxxxxxxxxx",
9  SecretKey: "xxxxxxxxxxxxxxx",
10});
11/* 存储桶名称 */
12const bucket = "hylcdn-1305519392";
13/* 存储桶所在地域 */
14const region = "ap-beijing";
15
16// 需要上传的文件夹地址
17const filePath = path.resolve("build/");
18
19// 批量删除文件,先查后删
20const deleteOldFile = () => {
21  return new Promise((resolve) => {
22    cos.getBucket(
23      {
24        Bucket: bucket,
25        Region: region,
26        Prefix: "static/", //要清理的目录
27        Marker: "static/", //要清理的目录
28        MaxKeys: 1000,
29      },
30      function (listError, listResult) {
31        if (listError) return console.log("list error:", listError);
32        var objects = listResult.Contents.map(function (item) {
33          return { Key: item.Key };
34        });
35        if (objects.length) {
36          cos.deleteMultipleObject(
37            {
38              Bucket: bucket,
39              Region: region,
40              Objects: objects,
41            },
42            function (delError, deleteResult) {
43              if (delError) {
44                console.log(delError);
45              }
46              if (deleteResult?.statusCode === 200) {
47                console.log("清理原static目录成功!");
48                resolve();
49              }
50            }
51          );
52        } else {
53          console.log("目录下无资源,无需删除!");
54          resolve();
55        }
56      }
57    );
58  });
59};
60
61//单个上传文件
62const uploadFile = (pathItem) => {
63  cos.putObject(
64    {
65      Bucket: bucket,
66      Region: region,
67      Key: `static/${pathItem.split("static/")[1]}`, //上传到 存储桶 的路径 *
68      StorageClass: "STANDARD",
69      Body: fs.createReadStream(pathItem), // 被上传的 文件对象
70    },
71    function (err, data) {
72      if (data?.statusCode === 200) {
73        console.log(`上传${pathItem.split("/").pop()}到cdn成功!`);
74      }
75    }
76  );
77};
78
79const playUpload = async () => {
80  // 先删除原来的static
81  await deleteOldFile();
82  // 获取即将上传的所有文件路径
83  const fileData = await fileDisplay(filePath);
84  // 开始逐一上传
85  fileData.forEach((item) => {
86    uploadFile(item);
87  });
88};
89
90playUpload();
91

2.4 效果

运行脚本

3. 修改项目的静态文件指向

项目默认一般是指向根目录,我们把它改成我们的存储桶cdn链接(这里我使用了自定义域名,1.3那个访问域名也可以)

以creat-react-app为例

效果,使用了cdn链接后资源加载的非常快

4. 自动化部署

修改package.json scripts配置

将打包,上传cdn,上传服务器 三个脚本合成一个指令

一条龙服务

附上我上传项目到服务器的脚本配置

代码语言:javascript复制
1const scpClient = require("scp2")
2const ora = require("ora")
3const server = {
4    host:"xx.xx.xx.xx",//服务器IP
5    port:22,//服务器端口
6    username:"root",//服务器ssh登录用户名
7    password:"xxx",//服务器ssh登录密码
8    path:"/www/wwwroot/my-blog"//服务器web目录
9}
10const loading = ora("正在部署至 "   server.host )
11loading.start()
12scpClient.scp("build/", server ,(err)=>{
13loading.stop()
14    if(err) {
15        console.log("部署失败")
16        throw err
17    }else {
18        console.log("部署成功")
19    }
20})
21

可能遇到的问题

1、产生了额外的流量费,欠费。

因为这个存储桶会产生四种流量费,建议都购买一下

  • 标准存储容量费用:这个开始会自动送你50个G
  • CDN 回源流量费用:这个需要买,一年十块左右
  • 标准存储请求费用:一年一块钱
  • 外网下行流量费用:一个月三块左右

0 人点赞