七牛云是国内算是挺不错的图片存储服务器,免费用户能拥有10G空间,每个月10G的下载流量,对于个人用户用于做个小博客,小网站来说,已经够了。
但是,七牛的官方开发文档真心会看得一头雾水。
于是,先记录下来这次传图的过程。
在上传图片之前,需要准备两样东西:
- AccessKey
- SecretKey
其中, AccessKey 和 SecretKey 能在 个人中心 > 秘钥管理中获得,如图。
- 创建空间 并 创建配置文件
- 选择 资源主页 ,再选择 立即添加,或者选择 对象存储 ,然后选择 添加 。
- 然后填上空间的名字,选择区域即可。
- 其中,空间的名字是我们使用代码上传至七牛服务器的第三个参数 Bucket
- 可以将这3个常量存储在配置文件config.qiniu.php中
define('QINIU_SECRET_KEY', 'YOUR_SK'); define('QINIU_ACCESS_KEY', 'YOUR_AK'); define('QINIU_DOMAIN', 'YOUR_QINIU_DOMAIN'); define('QINIU_BUCKET', 'YOUR_BUCKET_NAME');
- 获取上传凭证
- 上传凭证的作用:
客户端上传前需要先从服务端获取上传凭证,并在上传资源时将上传凭证作为请求内容的一部分。不带凭证或带非法凭证的请求将返回 HTTP 错误码 401,代表认证失败。
生成规则:
1.构造上传策略:
上传策略是资源上传时附带的一组配置设定。通过这组配置信息,七牛云存储可以了解用户上传的需求:它将上传什么资源,上传到哪个空间,上传结果是回调通知还是使用重定向跳转,是否需要设置反馈信息的内容,以及授权上传的截止时间等等。
{ "scope": "<Bucket string>", "deadline": <UnixTimestamp uint32>, "insertOnly": <AllowFileUpdating int>, "endUser": "<EndUserId string>", "returnUrl": "<RedirectURL string>", "returnBody": "<ResponseBodyForAppClient string>", "callbackUrl": "<RequestUrlForAppServer string>", "callbackHost": "<RequestHostForAppServer string>", "callbackBody": "<RequestBodyForAppServer string>", "callbackBodyType": "<RequestBodyTypeForAppServer string>", "callbackFetchKey": <RequestKeyForApp int> "persistentOps": "<persistentOpsCmds string>", "persistentNotifyUrl": "<persistentNotifyUrl string>", "persistentPipeline": "<persistentPipeline string>", "saveKey": "<SaveKey string>", "fsizeMin": <FileSizeMin int64>, "fsizeLimit": <FileSizeLimit int64>, "detectMime": <AutoDetectMimeType int>, "mimeLimit": "<MimeLimit string>" "deleteAfterDays": "<deleteAfterDays int>" }
- 如现有如下上传策略:
$putPolicy = array( 'scope' => QINIU_BUCKET.':'.$filename , 'deadline' => time()+3600 , 'returnBody' => '{ "name": $(fname), "file_url": $(x:file_url) }' );
- 该上传策略定义了:
1. 指定了图片上传至`QINIU_BUCKET`存储空间中,同时,该token只允许文件名为 `$filename` 的文件上传。 2. token有效时间为1个小时。 3. 设置返回信息,返回上传的文件的文件名,和自定义参数中的 `file_url`
- 将上传策略序列化成为JSON格式:
- 用户可以使用各种语言的 JSON 库,也可以手工拼接字符串。序列化后,应得到如下形式的字符串(字符串值以外部分不含空格或换行):
$putPolicy = json_encode($putPolicy);
- 或
$putPolicy = '{ "scope": "my-bucket:sunflower.jpg", "deadline":1451491200, "returnBody": "{ \"name\":$(fname), \"size\":$(fsize), \"w\":$(imageInfo.width), \"h\":$(imageInfo.height), \"hash\":$(etag) }" }'
- 对 JSON 编码的上传策略进行URL安全的Base64编码,得到待签名字符串:
- 官方给的demo代码为:
encodedPutPolicy = urlsafe_base64_encode(putPolicy)
- 运行之后,发现 urlsafe_base64_encode 这个函数是自定义的,估计相当于将 +,/号转换为 -,_
function _urlsafe_base64_encode($str){ $find = array('+', '/'); $replace = array('-', '_'); return str_replace($find, $replace, base64_encode($str)); }
- 使用SecretKey对上一步生成的待签名字符串计算HMAC-SHA1签名:
- 官方给的demo代码为:
sign = hmac_sha1(encodedPutPolicy, QINIU_SECRET_KEY)
- 然而, hmac_sha1 这个函数也不是php自带的。经过搜索发现,其实PHP5.1.2之后的版本内置了直接产生的函数,只是名字不一样罢了: hash_hmac,因此需要将这里修改为:
$sign = hash_hmac('sha1' ,$encodedPutPolicy, QINIU_SECRET_KEY, true);
- 第一个参数为哈希算法名(支持md5,sha256,haval160,4等,具体可到 hash_algos()中查询);第二个参数为需要进行哈希的信息;第三个参数为秘钥;第四个参数为输出格式(true为输出二进制,false为输出16进制)
- 对签名进行URL安全的Base64编码:
- 官方代码:
encodedSign = urlsafe_base64_encode(sign)
- 这里的 urlsafe_base64_encode 依然为上述的自定义函数。
- 将AccessKey、encodedSign 和 encodedPutPolicy 用英文符号 : 连接起来:
$uploadToken = QINIU_ACCESS_KEY . ':' . $encodedSign . ':' . $encodedPutPolicy
- 返回token至客户端
echo json_encode(array('token' => $uploadToken, 'key' => $filename, 'fileurl' => QINIU_DOMAIN));
- 这里返回了文件名和文件url,主要是因为,保证文件在七牛中的唯一性,和可以随时更改七牛的空间访问地址。
- 上传图片
- 使用js直接上传图片至七牛服务器他的过程为:
- 向服务器请求 uploadToken =>
- 获取 ‘uploadToken` 后上传图片 =>
- 上传成功,显示图片。
- 这里没有使用 zepto jquery 这种库,所以浏览器的兼容性为兼容 FormData 的现代浏览器
- 使用 xhr 和 FormData 进行异步传输数据。
function ajax(options){ options.start && options.start.call('start'); //执行上传操作 var xhr = new XMLHttpRequest(); xhr.open("post", options.url, true); xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); xhr.onreadystatechange = function() { if (xhr.readyState == 4) { returnDate = JSON.parse(xhr.responseText); options.success && options.success.call('success', returnDate); }; }; //表单数据 var fd = new FormData(); for (k in options.data) { fd.append(k, options.data[k]); } fd.append('file', options.file); //执行发送 result = xhr.send(fd); }
新建一个表单 form
<form action="" method="post" name="upload_form" hidden> <input type="file" name="file"> <input type="hidden" name="key" value=""> <input type="hidden" name="x:file_url" value=""> <input type="hidden" name="token" value=""> </form>
- 给上传文件的按钮绑定一个 change 时间:
file.addEventListener('change', function(e){ var selected_file = e.target.files[0]; // 先请求服务器获取token ajax({ url: '/upload.php', data: { filename: selected_file.name }, start: function(){ console.log('start to get uploadToken'); }, success: function(data){ // 给表单中的参数赋值 form.key.value = data.key; form.file_url.value = data.fileurl+data.key; form.token.value = data.token; // 执行上传图片操作 uploadImage(selected_file) } }) })
开始上传文件至七牛
function uploadImage(file){ ajax({ // 如果 url: 'http://upload.qiniu.com/', // url: 'https://up.qbox.me', data: { file: file, key: form.key.value, 'x:file_url': form.file_url.value, token: form.token.value, }, start: function(){ console.log('start to upload Image to Qiniu'); }, success: function(data){ // 给表单中的参数赋值 console.log(data); image.src = data.file_url } }) }
最终实现
希望本文能帮助到您!
点赞+转发,让更多的人也能看到这篇内容(收藏不点赞,都是耍流氓-_-)
关注 {我},享受文章首发体验!
每周重点攻克一个前端技术难点。更多精彩前端内容私信 我 回复“教程”
本文暂时没有评论,来添加一个吧(●'◡'●)