likes
comments
collection
share

node开发一个图片服务器(koa) | 【图片优化】(三)

作者站长头像
站长
· 阅读数 13

前言

一名正在自由职业的程序员的独立开发之路 每天100元的图片流量费用 逼得我不得不做图片优化 目前已经全部优化完成 希望我的经历能给你带来帮助 这是图片优化的第三篇

说明

本篇主要记录服务端如何实现一个图片服务器,并接入别人的CND

我这边用Nginx实现图片服务,用Koa实现图片的上传,用了一家服务商接入CND

这样虽然我的服务器只有 1M的宽带,也能实现 每天60G流量的暴击

是不是很6

下面是我服务器的配置

图片优化系列文章

Nginx 实现图片服务(主要做静态服务)

Nginx来实现 图片的获取,主要有以下好处

  1. Nginx服务与图片上传的服务分离,确保稳定性,万一上传的那个Node服务崩了,咋办
  2. Nginx直接做静态服务器,应该比自己启的Node服务应该更加稳定

Nginx配置如下(并配置HTTPS)

# 配置静态服务
    server {
            listen       80;
            server_name  abc.com;
            #access_log  logs/host.access.log  main;

            location / {
                    root  /image/;
                    autoindex on;
            }
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                    root   html;
            }
    }
    
    # 同时配置 HTTPS
   server {
    listen 443 ssl;
    server_name abc;
    ssl_certificate  /cert/abc.pem;
    ssl_certificate_key /cert/abc.key;
    ssl_session_timeout 5m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #按照这个协议配置
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;#按照这个套件配置
    ssl_prefer_server_ciphers on;

        location / {
                        root  /image/;
                        autoindex on;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
                        root   html;
        }
}
    
    

用Koa实现图片上传

用Koa做图片上传有很多的中间件,也可以自己写

我一开始用的是 koa-body,能实现自定义图片名字,但是无法根据前端传递的参数去自定义图片的名字,不符合我的需求

后来用的koa-multer,其他的不太了解

直接上代码了

const multer = require("koa-multer");
# uploadDir 为上传到你的哪个目录
let storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, uploadDir);
  },
  filename: function (ctx, file, cb) {
    const fileNameDate = dayjs().format("YYYYMMDD_HHmmss_SSS")
    fileName = `${fileNameDate}_${file.originalname}`
    if(ctx.body.prefix) fileName = `${ctx.body.prefix}_${fileName}`
    # fileName 为重新命名的文件名,可以自定义
    # prefix 这个参数是客户端传过来的
    cb(null, fileName);
  },
});
# 图片的配置
let upload = multer({
    storage: storage,
    limits: {
      fileSize: 1024 * 60, // 这样算下来就是 KB(限制在60K)
    },
  });
router.post("/uploadMulter", upload.single("file"), async (ctx) => {
    try {
         console.log("data", ctx.req.file.filename);
        let basename = ctx.req.file.filename
        let url = `http://abc/${basename}`
          ctx.body = {
            code: 200,
            msg: "上传成功",
            url,
          };
    } catch (error) {
          ctx.body = {
            code: 400,
            msg: "上传失败",
          };
    }

   });

对接CND

CDN有很多的厂家,但是我最后找了一个小公司,别问为什么,就是为了省钱

酷乐云

接入流程

第一步 解析一下TXT记录

 node开发一个图片服务器(koa) | 【图片优化】(三)

第二步 解析 cname(最终你最后要用的CDN地址的域名)

比如用 cdn.baidu.com来举例

我们将cdn.baidu.com解析到 官网后台给你的一个 字符串

 node开发一个图片服务器(koa) | 【图片优化】(三)

第三步 上传HTPPS的证书到后台

这个直接在阿里云后台,自己申请hpps证书下载下来

然后在后台将里面的 值分别传上去就行了

第四步 把 cdn.baidu.com 解析到 自己的服务器地址

即使跟上面 nginx配置的 http的那个一模一样

        server {
                listen       80;
                server_name  cdn.baidu.com;
                #access_log  logs/host.access.log  main;

                location / {
                        root  /image/;
                        autoindex on;
                }
                error_page   500 502 503 504  /50x.html;
                location = /50x.html {
                        root   html;
                }
        }

最后遇到的问题

到了这一步

当你访问 https://cdn.baidu.com/111.jpg,第一次这个链接还是转到你自己的服务器上面

这个时候CDN 服务器会自动把这个路径的资源 加载到它的各个节点的CDN服务器

当第二次访问 https://cdn.baidu.com/111.jpg这个链接,就直接访问的CND服务器,不会再访问你自己的服务器了

这样就解决了自己服务器性能问题和宽带问题

这里有个坑

因为是小公司,它这需要加载好几次才能资源真正加载过去

当然它也提供直接手动去把资源同步过去,对于不太常变资源,还是很不错的

用七牛云备份,防止意外情况

因为还是不太放心,所以我把图片在七牛服务器也备份了一份,保险一点

直接读取相关URL,然后批量上传到七牛服务器

下面直接放七牛的代码

node 获取token

npm i qiniu
node 生成token
    var config = {
      "AccessKey": "",
      "SecretKey": "",
      "Bucket": "",
      "Port": ,
      "UptokenUrl": "",
      "Domain": ""
    }

    var mac = new qiniu.auth.digest.Mac(config.AccessKey, config.SecretKey);
    var config2 = new qiniu.conf.Config();
    // 这里主要是为了用 node sdk 的 form 直传,结合 demo 中 form 方式来实现无刷新上传
    config2.zone = qiniu.zone.Zone_z2;
    var options = {
        scope: config.Bucket,
        // deleteAfterDays: 1, 这个代表1天后自动删除
        returnBody:
            '{"key":"$(key)","hash":"$(etag)","fsize":$(fsize),"bucket":"$(bucket)","name":"$(x:name)"}'
    };
    var putPolicy = new qiniu.rs.PutPolicy(options);
    
  router.post("/getQiuniuToken", async (ctx) => {
    try {
      var token = putPolicy.uploadToken(mac);
          ctx.body = {
            code: 200,
            token,
          };
    } catch (error) {
          ctx.body = {
            code: 400,
      
          };
    }

   });

web上传

# web上传
npm i qiniu
    /**
     * 
     * 获取七牛上传的图片
     * 1.现货区token
     * 2.上传
     */
    submitImgForQiniu(file){
      return new Promise(async (resolve,reject)=>{
        let resToken = await this.$api.getQiuniuToken()
        console.log('resToken ===',resToken)
        var putExtra = {customVars: {} };
            var config = {
                useCdnDomain: true,
                disableStatisticsReport: false,
                retryCount: 6,
                region: qiniu.region.z2
            };
            var token = resToken.uptoken;
            var domain = resToken.domain;
            // let key = `${new Date().getTime()}-${(Math.random().toFixed(3)) * 1000}-${file.name}`
            // 保持原来的名字
            let key = `${file.name}`
            putExtra.customVars["x:name"] = key.split(".")[0];
            putExtra.customVars["x:year"] = '2023';
            console.log('上传参数 ... key', key)
            let observable = qiniu.upload(file, key, token, putExtra, config);
            var subObject = {
                next: (response) => {
                    console.log('next ...', response)
                },
                error: (error) => {
                    console.log('error ...', error)
                    reject()
                },
                complete: (res) => {
                    let url = `http://你七牛设置的域名/${res.key}`;
                    console.log('res ...', res)
                    console.log('url ...', url)
                    resolve({upload_url:url}) 
                }
            };
            let subscription = observable.subscribe(subObject); 
      })
    },

总结

完成了图片上传的服务端

虽然我的服务器不够我的业务量

但是根据自身业务的特点 ,并且借助CDN 目前每天的流量在50G

这是一个【图片优化】系列文章的【第三篇】

转载自:https://juejin.cn/post/7242596613749866557
评论
请登录