react-native.jpeg
識兔,一款用來識別圖片的開源項目,在未來還會添加更多有意思的東西
歡迎加入QQ群397885169一起學習。
前言
在我最新開源的識兔項目中,最重要的功能就是識別圖片了,而圖片的識別過程如下
選中/拍攝 => 上傳圖片 => 后臺返回識別之后的url
第一步中可能遇到的坑,在我另一篇文章有過講解react-native-image-picker在iOS上閃退的解決辦法,如果還有其他的問題,歡迎在評論區提出。
第二步就是上傳圖片了,在本文中會給出兩種上傳圖片的方式。原生上傳圖片和使用react-native-fetch-blob
實現上傳圖片。
第三步,需要涉及一些后臺的東西和web加載的動畫,我的規劃是先將web的加載動畫寫出來,后續將nodejs
后臺的搭建和使用,再寫點東西。
注:本文中是將圖片上傳到七牛云。上傳到其他空間也是大同小異。
準備工作
不管是原生上傳還是使用第三方上傳,有個步驟都是不能省略的,那就是需要知道上傳到哪,哪怕在寫過要上傳到七牛,但七牛那么大,具體到哪個存儲空間這都是需要知道的。
在上傳之前除了要知道上傳的存儲空間之外,還要獲得七牛返回的參數,通過七牛返回的hash來真正的完成上傳,但這個獲取hash的過程不推薦在前端做處理,最好是放在后端(但如果非要放在前端也是沒問題的,代碼都是差不多的)。
下面的代碼,是我開源識兔的本地服務器代碼,如果遇到不明白的問題,可以在github上查看,或者加397885169一起討論
// 引入七牛,
var qiniu = require('qiniu');
// 引入uuid,用它構建唯一的key
var uuid = require('uuid');
var putPolicy;
// 唯一的key
var key = uuid.v4();
// 處理格式
key += '.jpeg';
// 通過七牛提供的方法,構建上傳策略函數,imagePutPolicy就是上傳的空間名
putPolicy = new qiniu.rs.PutPolicy(config.qiniu.imagePutPolicy + ":" + key);
var token = putPolicy.token()
// 返回key和token
return {
key : key,
token:token,
};
原生上傳方式
// 創建form表單
let body = new FormData();
// token和key都是通過七牛返回的參數
body.append('token',token);
body.append('key',key);
body.append('file',{
// 設定上傳的格式
type : 'image/jpeg',
// 通過react-native-image-picker獲取的圖片地址
uri : uri,
name : key,
});
// 開啟XMLHttpRequest服務
let xhr = new XMLHttpRequest();
/** 上傳到七牛云的地址 */
let url = Config.qiniu.upload;
// 開啟post上傳
xhr.open('POST',url);
// 如果正在上傳,返回上傳進度
if (xhr.upload){
xhr.upload.onprogress = (event)=>{
if (event.lengthComputable){
let perent = event.loaded / event.total.toFixed(2);
// 打印上傳進度
console.log(perent);
}
}
}
// 上傳過成功的返回
xhr.onload = ()=>{
// console.log(xhr.status);
// 狀態碼如果不等于200就代表錯誤
if (xhr.status !== 200){
alert('請求失敗');
console.log(xhr.responseText);
return;
}
if (!xhr.responseText){
alert('請求失敗');
console.log(xhr.responseText);
return;
}
// 服務器最后返回的數據
let response;
try{
// 將返回數據還原
response = JSON.parse(xhr.response);
console.log(response);
// ...通過返回數據做接下來的處理
}
// 發送請求
xhr.send(body);
}
react-native-fetch-blob
{
let token = data.data.token;
let key = data.data.key;
// 這里需要將'///'處理掉,因為使用wrap的時候,會再包裹一層
// 本文的fetch-blob使用的是0.10.4版本,據說其他版本不用添加下面的代碼。
let PATH = iOS?response.uri.replace('file:///',''):response.uri;
// 創建上傳的請求頭,使用fetch-blob必須要遵循name,data的格式,要不然就不成功。
let body = [{
name:'token',data:token,
}, {
name:'key', data:key,
},{
name: 'file',
filename: key || 'file',
data: RNFetchBlob.wrap(PATH)
}];
RNFetchBlob
.fetch('POST',url,{
// 上傳圖片要設置Header
'Content-Type' : 'multipart/form-data',
},body)
.uploadProgress((written, total) => {
// 本地查找進度
})
.progress((received, total) => {
let perent = received / total;
// 上傳進度打印
console.log(perent);
})
.then((response)=> response.json())
.then((response)=> {
// 上傳信息返回
console.log(response);
})
.catch((error)=>{
// 錯誤信息
console.log(error);
});
}
比較
原生的上傳方式對于開發過原生JavaScript
的人來說,其實更好理解,但對于沒有寫過原生js的童鞋,就需要去了解XMLHttpRequest
和它的一些api才能完成上傳的操作。
react-native-fetch-blob
封裝了上傳的功能,對于開發者來說,api更簡單,也更便于操作。唯一的缺點就是body必須按照官方提供的格式填寫,有一點不同都會報錯,作者之前就卡在這上面好長時間。
經過測試,4M以下的圖片好像是獲取不到上傳進度的,如果有更好的解決辦法,歡迎提出。
總結
本文是作者在上傳圖片過程中,對于兩種方式的總結,可能會有寫的不清楚或者不正確的地方,歡迎在評論區評論,或者加397885169一起討論。
作者以后會書寫更多有關react-native的文章。