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