本文首发于个人博客https://www.kagurakana.xyz/detail/e169338c7,如果对您有帮助,或者任何建议,请务必在小站流言,一起做朋友呀~~
图床介绍
图床是我这种小博客赖以生存的工具,他可以托管图片,减轻我的1核2g的辣鸡服务器的压力.目前我使用过的图床有sm.ms,和七牛cdn,而七牛不只可以托管图片,还可以托管各种静态资源,例如音频和视频等.并为其绑定加速域名.以下主要介绍七牛JavaScript-sdk和node-sdk.因为本博客采用了node作为后端.
十分鸡肋的是七牛cdn每个月只有10g的静态资源存储空间(不累加),用超出去会每个月交钱(10G大概1.5元,如果每个月存储100G也就15块),其他的作为小站来说基本不可能达到,具体资费请参照官网.
准备工作
1. 注册七牛账号,创建存储空间bucket
首先选择对象存储,并创建存储空间.
点击新建空间,进行一些简单的配置,如选择存储地理位置等,配置完成后就会看到下面的存储空间,此时已经可以手动添加图片进去了.
2. 绑定域名加速
在创建好bucket也就是存储空间之后,可以进行域名加速绑定,好处是可以使用自己的域名进行图片获取和上传.
绑定的域名需要在大陆进行ICP备案,我的域名是kagurakana.xyz,在阿里云购买,SSL证书是阿里云免费个人版证书,这种证书只支持单域名,不支持泛域名(*.domain.com),如果你和我一样需要https
协议来存储你的图片,除了本站域名(kagurakana.xyz)需要申请SSL证书之外,cdn域名(我的是cdn.kagurakana.xyz,可以在阿里云的dns解析中配置)也要申请SSL证书,假设你现在已经有了yourdomain.com
和cdn.yourdomain.com
的ssl证书.且主站yourdomain.com
已经在域名购买商的dns解析中和Nginx服务器中完成了配置(如何在主站中配置https和Nginx部署SSL我会在最近写一篇文章介绍),那么只需要关注cdn.yourdomain.com
的证书就好了,这个不需要进行配置,只要下载下来复制到七牛cdn中就好了,我会在后面介绍.
2.1 配置七牛云域名加速
可以按照喜好自行配置.
2.2 *申请该域名的SSL(HTTPS需要/HTTP可跳过)
在阿里云申请个人免费版SSL证书,填写证书域名为cdn.yourdomain.com
,其他默认就好,证书文件会自动关联到到你的cdn域名下.下载Nginx版的证书文件,其中会有一个.pem
文件和一个.key
文件.先保存在本地.
2.3 *在七牛CDN导入证书文件(HTTPS需要/HTTP可跳过)
把刚才先下载的.pem
中的内容用编辑器打开,复制到证书内容一栏,把.key
文件打开复制到证书密钥一栏,点添加.添加完成后应该可以看到cdn页面下的https证书多了一个可以选的,选择那个.
后面的原站配置选择七牛云存储,其他选择默认或者推荐就好.在高级配置中可选择域名防盗链,防止被引用过多产生更多费用,我配置了本站(kagurakana.xyz)和简书和七牛云这三个.
2.4 配置阿里云域名的DNS解析
在七牛的cdn配置完之后,要将图片cdn和主站DNS进行关联,在七牛完成之后,可以得到一个CNAME值,复制这个CNAME
上到阿里云的控制台,找到DNS,记录类型选择CNAME,将刚才的CNAME填入下面的记录字中.
等待DNS服务器更新(TTL时间)后,可以看到状态从等待CNAME成为了成功.
至此,准备阶段的工作全部完成,你可以用你自定义的域名来访问上传的图片了,然而这是不够的.我们还要解决图片拖拽自动上传的功能.
使用JavaScript-SDK和node-SDK完成自动上传
1. 后端鉴权
安装七牛cdn
npm install qiniu --save
创建qiniu.config.js
文件:
// /config/qiniu.config.js
module.exports = {
accessKey: '在七牛个人信息密钥管理中可以找到',
secretKey: '在七牛个人信息密钥管理中可以找到',
domain: '在bucket管理界面可以找到,可以看下面的图片',
options: {
scope: "kagurakana",//你的bucket空间的名称
expires: 3 * 3600,//单次鉴权有效期,在申请鉴权的多少喵内可以上传,可缺省,默认为1小时
//自定义返回参数,在上传成功后返回给前端,注意是字符串类型,是$()小括号不是大括号,大括号没试过不知道行不行.
//其中$(key),$(bucket),$(fname)是七牛中的默认变量
//
returnBody: `{"key":"$(key)",
"bucket":"$(bucket)",
"name":"$(fname)"}`
}
}
更详细的配置可以在官网里找到,这里只列的我的配置.
在router中引入
// /routes/update.js
let express = require('express');
let router = express.Router()
//导入之前的config
let opt = require('../config/qiniu.js')
let qiniu = require('qiniu');
//我自己的管理员权限认证中间件
const {loginCheckAdmin} = require('../midware/midware')
// 定义鉴权对象mac
let mac = new qiniu.auth.digest.Mac(opt.accessKey,opt.secretKey)
// 定义上传凭证
let putPolicy = new qiniu.rs.PutPolicy(opt.options)
let uploadToken = putPolicy.uploadToken(mac)
//处理get获取上传鉴权认证,我这里是管理员才能上传
//你也可以写中间件只能让注册用户上传.或者开放上传(避免滥用不推荐)
router.get('/uptoken',loginCheckAdmin,(req,res,next)=>{
res.header("Cache-Control", "max-age=0, private, must-revalidate");
res.header("Pragma", "no-cache");
res.header("Expires", 0);
if(uploadToken) {
res.json({uploadToken});
}
})
module.exports = router;
后端最简单的配置已经结束了,如果还需要添加文字或图片水印,裁剪图片,加滤镜,生成缩略图,覆盖重复文件可以参考node-SDK文档
.
2. 前端上传
前端使用了vue+axios,可以根据配置自行修改
npm install qiniu-js --save
封装网络请求请求鉴权
//封装网络请求request方法,仅提供参考.
// network/request.js
import axios from 'axios'
axios.defaults.withCredentials=true;//配置axios携带cookie
export function request(config){
const instance = axios.create({
baseURL:'https://yourdomaim.com/apis',
timeout:5000
})
//拦截
instance.interceptors.response.use(res=>{
if(res.data.errno!=404){
return res.data;
}else{
window.location.replace('/home')
}
})
return instance(config)
}
// network/imgUpdate.js
import { request } from './request'
export function getUploadToken(){
return request({
method:'get',
url:'你的后端接口/uptoken'
})
}
拖拽上传
首先来看一下sdk提供的上传函数:
qiniu.upload(file: blob, key: string, token: string, putExtra: object, config: object): observable`
上面的关键函数返回一个观察者对象(observable),该对象具有订阅(subscribe)方法,subscribe方法接收三个函数作为参数,分别在上传中,上传失败,上传成功后调用.
//界面.vue
<template>
<!-- 监听拖放事件 -->
<v-textarea @drop.prevent.stop="imgDrop" v-model="content" label="content"></v-textarea>
</template>
<script>
import { getUploadToken } from "network/imgUpdate";
import * as qiniu from "qiniu-js";
export default {
name: "BlogPost",
data() {
return {
upToken: "",
content:""
};
},
created() {
getUploadToken().then(res => {
//获取后台返回的七牛cdn uptoken
this.upToken = res.data.uploadToken;
});
},
methods: {
//这三个方法作为参数给七牛观察方法传递的,不能缺省
//上传错误处理调用的(七牛返回的错误信息)
next(res){
//可以自己log下res,是上传的进度什么的;
},
error(err) {
console.log(err);
},
//成功处理后调用的方法
complete(res) {
//url拼接,返回markdown格式字符串,content是双向绑定数据,更进一步,你可以根据输入的光标位置决定markdown位置
this.content += `![${res.name}](https://cdn.kagurakana.xyz/${res.name})`;
},
/**拖放监听处理chorme,其他未做适配 */
imgDrop(e) {
//这里如果console.log(e)里面dataTransfer的files数组是空的,不用管
let file = e.dataTransfer.files[0]; //获取拖放文件 Blob
if (this.upToken) {
//函数格式:qiniu.upload(file: blob, key: string, token: string, putExtra: object, config: object): observable
let observable = qiniu.upload(
file,
file.name,
this.upToken,
{ fname: file.name, params: {}, mimeType: null }, //putExtra
{ useCdnDomain: true } //config
);
//开始上传
observable.subscribe(this.next,this.error,this.complete);
}
}
}
};
</script>
<style lang='scss' scoped>
</style>
看一下效果:
更进一步,你可以添加剪贴板上传图片而不是拖拽上传,或者根据光标位置插入markdown而不是在末尾插入.