1、技术概述,描述这个技术是做什么?学习该技术的原因,技术的难点在哪里。控制在50-100字内。
上传文件是前端开发中经常遇到的一个问题。最近在做团队项目的时候,就遇到了用户头像存储的问题。因此我们考虑把图片上传交给第三方处理,此处采用七牛云进行图片存储,以及前端上传的方式。其实没啥难点,网络上也蛮多教程的(不乏错误案例),主要是对于我这个小白,一看到这么高大上的东西就望而生畏了,就这?我能搞定?嗯最后我还是搞定了。如果真的要说难点,请移步下文第3点。
2、技术详述,描述你是如何实现和使用该技术的,要求配合代码和流程图详细描述。可以再细分多个点,分开描述各个部分。
以下是通过前端js将文件直接上传到七牛云的流程图
- 准备工作
首先到七牛云上注册一个账号点击前往
然后新建存储空间(这里的存储空间名称要记住,之后在代码里面会用到)
so easy~~
小科普:Base64编码是把3个8位字节(38=24)转化为4个6位的字节(46=24),之后在6位的前面补两个0,形成8位一个字节的形式。 如果剩下的字符不足3个字节,则用0填充,输出字符使用’=’,因此编码后输出的文本末尾可能会出现1或2个’=’(如果还是不清楚的可以在控制台输出看看,会更加直观)。
好了,记住了嘛。一会我们要通过上面这个原理计算图片的文件流大小。
接下来就是获取服务器的上传token(需要用到七牛的AccessKey和SecretKey,这里是后台实现的,后端服务提供一个URL地址,供SDK初始化使用,前端通过Ajax 请求该地址后获得 upToken。)
- 关键代码
步骤:前端通过服务端请求token,然后再通过七牛云提供的接口进行上传,成功后取得hash和key。
后端controller
package com.memory.controller;
import com.memory.pojo.Qiniu;
import com.memory.utils.JsonResult;
import com.memory.utils.JsonUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.qiniu.util.Auth;
import com.qiniu.util.StringMap;
import java.util.UUID;
@Controller
@RequestMapping(value = "upload")
public class ImageUploadController {
private String AK = "PtpL4YaLivm6f0puAXE7iQdummwzGr-a";
private String SK = "KuMLbnjRtxO32NY2Wkk3ZlKiHD9CWkjN";
private String Bucket = "seven-days-memory";
@RequestMapping(value = "/getToken",method = RequestMethod.GET)
public @ResponseBody String getToken(){
long expireSeconds = 600; //过期时间
Auth auth = Auth.create(AK,SK);
StringMap putPolicy = new StringMap();
Qiniu qiniu = new Qiniu();
qiniu.setToken(auth.uploadToken(Bucket,null,expireSeconds,putPolicy));
qiniu.setKey(UUID.randomUUID().toString().replace("\\-",""));
return JsonUtils.toJSON(JsonResult.ok(qiniu));
}
}
前端上传
/*picBase是base64图片带头部的完整编码,myUptoken是从后端返回的upToken*/
function putb64(picBase,myUptoken) {
/*picUrl用来存储返回来的url*/
var picUrl;
/*把头部的data:image/png;base64,去掉。(注意:base64后面的逗号也去掉)*/
picBase = picBase.substring(22);
/*通过base64编码字符流计算文件流大小函数*/
function fileSize(str) {
var fileSize;
if (str.indexOf(‘=‘) > 0) {
var indexOf = str.indexOf(‘=‘);
str = str.substring(0, indexOf); //把末尾的’=‘号去掉
}
fileSize = parseInt(str.length - (str.length / 8) * 2);
return fileSize;
}
/*把字符串转换成json*/
function strToJson(str) {
var json = eval(‘(‘ + str + ‘)‘);
return json;
}
var url = "http://up.qiniu.com/putb64/" + fileSize(picBase);
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
var keyText = xhr.responseText;
/*返回的key是字符串,需要装换成json*/
keyText = strToJson(keyText);
/* 前面是七牛云空间网址,keyText.key 是返回的图片文件名,这里得到的picUrl就是我们需要的图片地址了*/
picUrl = "http://qazbuv5y2.bkt.clouddn.com/" + keyText.key;
/*调用个人中页面的js来保存头像并刷新页面*/
var personalWebview=plus.webview.getWebviewById("ll_personalCenter.html");
personalWebview.evalJS("refreshMyImage(‘"+picUrl+"‘)");
}
}
xhr.open("POST", url, false);
xhr.setRequestHeader("Content-Type", "application/octet-stream");
xhr.setRequestHeader("Authorization", "UpToken "+myUptoken);
xhr.send(picBase);
}
3、技术使用中遇到的问题和解决过程。要求问题的描述和解决有一定的内容,不能草草概括。要让遇到相关问题的人看了你的博客之后能够解决该问题。
问题描述:
一开始使用异步请求上传图片(xhr.open("POST", url, false)),发现只有偶尔几次能够正确运行,成功返回图片的url地址,大部分情况下是失败的:这时候客户端ajax的readystate一直是1,而且跳了2次1之后就没消息了。
解决:
后来经过多方查找资料,最终发现是异步请求问题:客户端需要把数据传到服务端后服务端经过验证再把结果传给客户端,可是使用异步的话就会使得客户端不会刻意等待服务端的响应。换句话说,就是像打仗一样,将军派通信兵去搬救兵,但是如果通信兵跑太慢,剩余兵力又太少,还没等救兵来,将军就已经没了,敌人也跑了。同样的,大多数情况下,还没等服务端把数据传过来,客户端已经GG了,也因此而出现了会有偶尔几次成功运行的情况。(真是坑爹)所以解决方法就是把异步改为同步,即true改为false。(哈哈哈这下真的屡试不爽了)
4、进行总结。
万事开头难啊。一开始担心自己做不到,做的过程也算不上顺利,但终于还是做到了。其实做完了便觉得没什么了,回头看看自己掉进的那些坑,甚至有些好笑。就冲着新get到的技能,值!
5、列出参考文献、参考博客(标题、作者、链接)。
参考文献 《七牛云官方示例》 《前端上传说明文档》
参考博客 标题:base64图片编码大小与原图文件大小之间的联系 作者:吃饭callme