一侠碧、 摘要
阿里oss提供了兩種上傳方式到云存儲(chǔ)一種是在Header中包含簽名,一種是在URL中包含簽名缠黍。區(qū)別如下
在URL中包含簽名
Header中包含簽名
二弄兜、 uniapp提供的上傳方式
重點(diǎn)說明,這個(gè)api是將本地資源上傳到開發(fā)者服務(wù)器瓷式,客戶端發(fā)起一個(gè) POST 請(qǐng)求替饿,其中 content-type 為 multipart/form-data。并且不可更改贸典,是不可更改视卢,網(wǎng)上很多教程修改Method方法,實(shí)際操作后廊驼,并不可行据过。
重點(diǎn)說明,這個(gè)api妒挎,可以自定義很多Method方法绳锅,但是data的請(qǐng)求的參數(shù)是
Object/String/ArrayBuffer 并且App不支持ArrayBuffer類型
上傳方式講解
- 有了以上兩個(gè)重要的前提分析后,我們來說一下酝掩,在app上鳞芙,如何使用uniapp進(jìn)行文件上傳
- 首先基于oss的上傳方式,由于我這里用的是Header中包含簽名的方式上傳的,所以积蜻,只能使用PUT進(jìn)行文件上傳闯割。
翻閱各種資料后,發(fā)現(xiàn)竿拆,uniapp并沒有很友好的支持PUT上傳文件的方式。插件市場(chǎng)大部分也并不能滿足需求宾尚。這里提一句OSS不支持同時(shí)在URL和Header中包含簽名只能選一種丙笋。所以插件市場(chǎng)上的那些插件,要視情況使用煌贴。
- 因?yàn)閡niapp對(duì)put上傳文件的支持有限御板,所以,最終采用內(nèi)嵌webview+XMLHttpRequest的方式來進(jìn)行PUT中的文件上傳牛郑。
- 由于怠肋,文件選擇我這里使用的是 uni.chooseImage(OBJECT)。這里有個(gè)坑淹朋,當(dāng)前api返回的文件笙各。并不能直接使用put上傳到oss。補(bǔ)充一點(diǎn)础芍,如果使用h5里面的<input type='file'/>標(biāo)簽回調(diào)的文件是可以上傳的杈抢。由于我這里有樣式的要求,所以仑性,并沒有直接使用input標(biāo)簽惶楼。
- 基于以上,查看相關(guān)文檔后诊杆,發(fā)現(xiàn)使用plus.io.resolveLocalFileSystemURL可以把本地文件路徑轉(zhuǎn)為File對(duì)象
resolveLocalFileSystemURL
- 這里還有一個(gè)坑歼捐,由于XMLHttpRequest/send(body),對(duì)body的格式有要求晨汹,所以豹储,我們使用plus獲取到的File文件依然不能直接使用。
在XHR請(qǐng)求中要發(fā)送的數(shù)據(jù)體. 可以是:
可以為Document
, 在這種情況下宰缤,它在發(fā)送之前被序列化.
為XMLHttpRequestBodyInit
, 從 per the Fetch spec (規(guī)范中)可以是Blob
,BufferSource
(en-US),FormData
,URLSearchParams
, 或者USVString
對(duì)象.
如果body沒有指定值颂翼,則默認(rèn)值為null
.
- 翻閱各種資料后,發(fā)現(xiàn)慨灭,可以把File對(duì)象重新轉(zhuǎn)換成XMLHttpRequest可識(shí)別的格式
//base64編碼格式轉(zhuǎn)file格式
var aa = evt.target.result;
var arr = aa.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
var fileResult = new File([u8arr], "filename.jpg", {
type: mime
});
最終的fileResult就是XMLHttpRequest可識(shí)別的文件對(duì)象了
轉(zhuǎn)換文件的完整代碼
document.addEventListener('UniAppJSBridgeReady', () => {
let {
res = {},
header,
fileList
} = plus.webview.currentWebview();
var uploadPromise = []
console.log("傳遞的參數(shù)" + JSON.stringify(fileList))
//res 為oss下發(fā)的預(yù)上傳的地址
//header為oss需要添加的請(qǐng)求頭application/octet-stream
//fileList 本地文件路徑集合朦乏。我這里為了演示,就用了第一個(gè)地址氧骤,實(shí)際項(xiàng)目中呻疹,可以使用批量上傳
document.addEventListener("plusready", onPlusReady(res, header, fileList[0].path), false);
});
// 擴(kuò)展API加載完畢,現(xiàn)在可以正常調(diào)用擴(kuò)展API
function onPlusReady(res, header, filePath) {
var uploadPromise = []
plus.io.resolveLocalFileSystemURL(filePath, function(entry) {
res.forEach((item, i) => {
console.log("》》》預(yù)上傳" + JSON.stringify(item))
console.log("》》》預(yù)上傳文件" + JSON.stringify(entry.isFile))
entry.file(function(file) {
var fileReader = new plus.io.FileReader();
console.log("getFile:" + JSON.stringify(file));
fileReader.readAsDataURL(
file); //以BASE64編碼格式讀取文件
fileReader.onloadend = function(evt) {
// console.log("evt.target" + evt.target);
// console.log("evt.target.result len = " +evt.target.result.length);
// console.log("evt.target.result = " +evt.target.result);
//base64編碼格式轉(zhuǎn)file格式
var aa = evt.target.result;
var arr = aa.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
var fileResult = new File([u8arr], "filename.jpg", {
type: mime
});
uploadPromise[i] = createUpload(fileResult, {
url: item.uploadUrl,
header: header
})
}
});
})
Promise.all(uploadPromise).then((res) => {
console.log("全部上傳成功了" + JSON.stringify(res))
location.href =
`callback?fileName=1233232323`;
}).catch((res) => {
})
}, function(e) {
console.log("Resolve file URL failed: " + e.message);
});
}
項(xiàng)目完整源碼筹陵,待補(bǔ)充