纯浏览器端实现七牛云私有图床为Hexo博客助力

纯浏览器端实现七牛云私有图床

页面展示

起因&需求

在利用hexo写博客的时候,图片是一个一直让人头疼的问题。我们对图片有这样的需求:

  • 图片不存放在本地而是存放在云端
  • 可以获取到图片的访问链接
  • 自动转变为符合markdwon语法的图片格式
  • 支持截图后直接复制粘贴即可快速得到想要的图片格式
  • 考虑到稳定性及维护性,不使用网上免费提供的图床
  • 要求在浏览器端实现上述功能,不能有后端服务器参与。(降低成本投入)

    准备

  • 软件准备:浏览器、Submine
  • 前端框架:zui框架
  • 资源准备:七牛云个人10G免费对象存储空间、Coding静态资源托管…

    思路

  • html页面代码
    • ui布局
      • 页面概述
      • 图片预览区域
      • 上传进度条
      • 图片链接
    • js功能实现
      • 监听浏览器粘贴
      • 上传图片

重难点

七牛云的图片上传机制

在浏览器端实现搭建七牛云私有图床,重点在于七牛云的图片上传机制,也就是说怎样把图片上传到七牛云自己账号里的对象储存空间里。
参考七牛云官方给出的上传策略:https://developer.qiniu.com/kodo/manual/1206/put-policy
我们构造上传策略即putPolicy,且putPolicy里至少需要包含scope、deadline信息
为使得上传的每一个图片的文件名称唯一,在上传图片时需要为其指定key值,即你需要指定上传图片名称,该名称不得与以前的图片名称重复,可利用时间戳作为图片文件名实现,该key值包含在scope里。
因此利用js我们构造的putPolicy对象如下:

1
2
3
4
5
var timestamp=Math.round(new Date().getTime() / 1000);
var key = new Date().format("yyyy-MM-dd")+"/"+timestamp+".jpg";
var putPolicy ={};
putPolicy.scope="blog"+":"+key;
putPolicy.deadline=timestamp+3600;//必须是数值类型非字符串

在此之后,原则上我们需要从自己的服务器(然并没有)获取上传凭证,并在上传图片时将上传凭证作为请求内容的一部分。
这里我们直接在浏览器上实现上传凭证token的计算。(所以七牛云访问公钥会直接暴露在浏览器html页面源码里,极不安全,极不推荐,但是我喜欢,所以叫私有云图床。)
参考七牛云官方给出的上传凭证算法:https://developer.qiniu.com/kodo/manual/1208/upload-token
分为六步:

  1. 构造上传策略putPolicy,上面已叙述。
  2. 将上传策略序列化成为JSON:

    1
    var put_policy = JSON.stringify(putPolicy);
  3. 对 JSON 编码的上传策略进行URL 安全的 Base64 编码,得到待签名字符串

    1
    var encoded = base64encode(utf16to8(put_policy));
  4. 使用访问密钥(AK/SK)对上一步生成的待签名字符串计算HMAC-SHA1签名:

    1
    var hash = CryptoJS.HmacSHA1(encoded, secretKey);
  5. 对签名进行URL安全的Base64编码:

    1
    var encoded_signed = hash.toString(CryptoJS.enc.Base64);
  6. 将访问密钥(AK/SK)、encodedSign 和 encodedPutPolicy 用英文符号 : 连接起来::

    1
    var upload_token = accessKey + ":" + safe64(encoded_signed) + ":" + encoded;

有了token和图片之后,再通过js构造XMLHttpRequest()请求指定七牛云服务器可以实现图片上传。下面是对应的上传代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
var Qiniu_UploadUrl = "https://up.qiniup.com"
//普通上传
var Qiniu_upload = function(f, token, key) {
var xhr = new XMLHttpRequest();
xhr.open('POST', Qiniu_UploadUrl, true);
var formData, startDate;
formData = new FormData();
if (key !== null && key !== undefined) formData.append('key', key);
formData.append('token', token);
formData.append('file', f);
var taking;
xhr.upload.addEventListener("progress", function(evt) {
if (evt.lengthComputable) {
var nowDate = new Date().getTime();
taking = nowDate - startDate;
var x = (evt.loaded) / 1024;
var y = taking / 1000;
var uploadSpeed = (x / y);
var formatSpeed;
if (uploadSpeed > 1024) {
formatSpeed = (uploadSpeed / 1024).toFixed(2) + "Mb\/s";
} else {
formatSpeed = uploadSpeed.toFixed(2) + "Kb\/s";
}
var percentComplete = Math.round(evt.loaded * 100 / evt.total);
document.getElementById("progressbar").style="width: "+percentComplete+"%";
}
}, false);
xhr.onreadystatechange = function(response) {
if (xhr.readyState == 4 && xhr.status == 200 && xhr.responseText != "") {
var blkRet = JSON.parse(xhr.responseText);
console && console.log(blkRet);
} else if (xhr.status != 200 && xhr.responseText) {
}
};
startDate = new Date().getTime();
xhr.send(formData);
};

完整的js代码流程

  1. 复制粘贴事件开始
  2. 判断是否为文件类型
  3. 利用FileReader(),读取base64数据作img的src显示
  4. 显示预览图片
  5. 根据时间生成key值(即上传后存储的文件名,唯一)
  6. 构造上传策略putPolicy,包含scope、deadline等
  7. 加密数据并计算token
  8. base64数据转文件,预上传数据
  9. 带token上传图片至七牛云服务器
  10. 显示图片链接
  11. markwon图片链接写入剪贴板
  12. 设置进度条

备注

为了使浏览器支持hmac-sha以及enc-base64编码至少需要引入CryptoJS中的下述代码

1
2
3
<script type="text/javascript" src="hmac-sha1.js"></script>
<script type="text/javascript" src="core-min.js"></script>
<script type="text/javascript" src="enc-base64.js"></script>