Android 開發(fā) 使用WebUploader解決安卓微信瀏覽器上傳圖片中遇到的bug
先給大家分析下微信瀏覽器上傳圖片bug的原因
微信在新版本中采用的是自己的X5內(nèi)核瀏覽器,而在較老的版本中還有可能是安卓的原生瀏覽器。具體的環(huán)境我也不太了解,但是經(jīng)過實(shí)際多臺(tái)安卓機(jī)型的測(cè)試,我采取的方案可以基本確保在安卓機(jī)中微信瀏覽器的成功上傳。蘋果機(jī)型沒問題,因?yàn)槲⑿诺膇os客戶端使用的是Safari的內(nèi)核,沒有各種坑,且效果最好。
這里給出一個(gè) WebUploader 官方關(guān)于移動(dòng)端適配的 issues 鏈接。里面提供的方法確實(shí)有效,但就是解決的方案并沒有很清楚的展示出來,從該issues中有好幾個(gè)人用戶提出如何修改就能知道了。
開始時(shí)遇到的問題
環(huán)境
后臺(tái)使用 Spring MVC [V 4.08],前端使用一個(gè)開源的 HTML5 框架
問題
ios可完美上傳,安卓手機(jī)一半以上不太支持,出現(xiàn)進(jìn)度條卡死,圖片無法上傳成功而且只能上傳png格式圖片的問題(后來證明是由于壓縮失敗引起的,在解決中詳細(xì)指出)。發(fā)布到服務(wù)器上正式運(yùn)營(yíng)以后,發(fā)現(xiàn)部分用戶只填寫了文字信息,無法上傳圖片,不好統(tǒng)計(jì)數(shù)據(jù),但是這樣的 BUG 率顯然是不行的,接下來就給出我的解決方案吧,經(jīng)過實(shí)際測(cè)試應(yīng)該是沒問題的,不保證完全有效,因?yàn)樵聿皇翘宄?,僅供參考。
后來的解決方案
第一步,sendAsBinary: true
我先是按照 issues 中給出的第一個(gè)解決方法,設(shè)置 sendAsBinary: true,后臺(tái)不做任何修改的情況下會(huì)產(chǎn)生 500 的錯(cuò)誤,但是此時(shí)解決了進(jìn)度條卡死的問題(當(dāng)然??!圖片直接就上傳失敗了?。鶕?jù)issues中 2betop 的回答,此時(shí)獲取文件應(yīng)該是直接獲取文件的二進(jìn)制流。
之前獲取圖片的方式是使用 Spring 自帶的 MultipartHttpServletRequest 將 HttpServletRequest 的實(shí)例 request 轉(zhuǎn)換,然后獲取多個(gè)文件的信息。下方代碼根據(jù)實(shí)際代碼刪減不必要的細(xì)枝末節(jié)得出。
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request; // 獲取上傳文件的列表 Map<String, MultipartFile> fileMap = multipartRequest.getFileMap(); // 圖片上傳前的原始名 String originalName; // 循環(huán)獲取多文件上傳時(shí)文件列表中的每個(gè)文件對(duì)象 for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) { // 上傳文件 MultipartFile mf = entity.getValue(); // 文件上傳前的原始名 originalName = mf.getOriginalFilename(); // 文件擴(kuò)展名 String fileExt = originalName.substring(originalName.lastIndexOf(".") + 1).toLowerCase(); // 文件的絕對(duì)路徑File File uploadFile = new File(uploadAbsolutePath + "/" + newName); try { FileCopyUtils.copy(mf.getBytes(), uploadFile); } catch (IOException ioException) { logger.error("圖片保存到文件夾中出錯(cuò)!", ioException); } catch (Exception e) { logger.error("文件沒有復(fù)制到指定的目錄下", e); } }
這是原本的獲取方式,500 報(bào)錯(cuò)時(shí)指示是第一行代碼出錯(cuò),無法轉(zhuǎn)換,因?yàn)榇藭r(shí) WebUploader 在設(shè)置了 sendAsBinary: true后 并沒有使用 content-type: multipart/form-data 上傳文件,而是 content-type: application/ocet-stream,源碼中也是這么寫的,但是實(shí)際獲取的請(qǐng)求頭中并沒有看到這個(gè)字段,而只是圖片的類型.下列給出我使用 Chrome 的 devTools 保存下來的請(qǐng)求信息,只貼出 headers 中的字段值(針對(duì)同一個(gè)上傳 API 提出請(qǐng)求):
500 錯(cuò)誤時(shí)的請(qǐng)求頭
"url": "http://localhost:8787/lostFound/front/release/upload?releaseType=0&orderId=330&id=WU_FILE_1&name=20140120_035024000_iOS.jpg&type=image%2Fjpeg&lastModifiedDate=Sat+Jan+31+2015+01%3A32%3A34+GMT%2B0800+(%C3%A4%C2%B8%C2%AD%C3%A5%C2%9B%C2%BD%C3%A6%C2%A0%C2%87%C3%A5%C2%87%C2%86%C3%A6%C2%97%C2%B6%C3%A9%C2%97%C2%B4)&size=81666", "httpVersion": "HTTP/1.1", "headers": [ { "name": "Origin", "value": "http://localhost:8787" }, { "name": "Accept-Encoding", "value": "gzip, deflate" }, { "name": "Host", "value": "localhost:8787" }, { "name": "Accept-Language", "value": "zh-CN,zh;q=0.8" }, { "name": "User-Agent", "value": "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1" }, { "name": "Content-Type", "value": "image/jpeg" }, { "name": "Accept", "value": "*/*" }, { "name": "Referer", "value": "http://localhost:8787/lostFound/" }, { "name": "Cookie", "value": "JSESSIONID=2839511C91E9ECE62D155C6EE18F3259; JSESSIONID=64B53863E1C7D82B96927F298A864E18" }, { "name": "Connection", "value": "keep-alive" }, { "name": "Content-Length", "value": "81666" } ], "queryString": [ { "name": "releaseType", "value": "0" }, { "name": "orderId", "value": "330" }, { "name": "id", "value": "WU_FILE_1" }, { "name": "name", "value": "20140120_035024000_iOS.jpg" }, { "name": "type", "value": "image%2Fjpeg" }, { "name": "lastModifiedDate", "value": "Sat+Jan+31+2015+01%3A32%3A34+GMT%2B0800+(%C3%A4%C2%B8%C2%AD%C3%A5%C2%9B%C2%BD%C3%A6%C2%A0%C2%87%C3%A5%C2%87%C2%86%C3%A6%C2%97%C2%B6%C3%A9%C2%97%C2%B4)" }, { "name": "size", "value": "81666" } ], "bodySize": 0
在不修改 sendAsBinary: true 之前成功上傳的請(qǐng)求頭
"url": "http://localhost:8787/lostFound/front/release/upload", "httpVersion": "HTTP/1.1", "headers": [ { "name": "Origin", "value": "http://localhost:8787" }, { "name": "Accept-Encoding", "value": "gzip, deflate" }, { "name": "Host", "value": "localhost:8787" }, { "name": "Accept-Language", "value": "zh-CN,zh;q=0.8" }, { "name": "User-Agent", "value": "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1" }, { "name": "Content-Type", "value": "multipart/form-data; boundary=----WebKitFormBoundaryLeVpfViKLf1xLdIr" }, { "name": "Accept", "value": "*/*" }, { "name": "Referer", "value": "http://localhost:8787/lostFound/" }, { "name": "Cookie", "value": "JSESSIONID=A76C40D04276501F54675AA02AE61467; JSESSIONID=64B53863E1C7D82B96927F298A864E18" }, { "name": "Connection", "value": "keep-alive" }, { "name": "Content-Length", "value": "44210" } ], "queryString": [], "bodySize": 929,
比較兩者的區(qū)別,發(fā)現(xiàn)區(qū)別:
content-type: 修改為 sendAsBinary: true 以后,這個(gè)值變?yōu)?image/jpeg, 而之前是 multipart/form-data,所以不能再使用 MultipartHttpServletRequest,后端獲取改為獲取文件流。
queryString:?jiǎn)⒂枚M(jìn)制上傳以后,參數(shù)直接添加到 Url 中。
bodySize:?jiǎn)⒂弥笞優(yōu)?0,啟用之前不為 0
先修改后端獲取方式,代碼更改如下:
File file = new File(uploadAbsolutePath); if (!file.exists() && !file.mkdirs()) { // 如果file對(duì)象不存在,那么就將該對(duì)象的路徑名中不存在的文件夾目錄建立出來 } // 文件擴(kuò)展名 String fileExt = name.substring(name.lastIndexOf(".") + 1).toLowerCase(); // 文件的絕對(duì)路徑File File uploadFile = new File(uploadAbsolutePath + "/" + newName); try { // 將上傳的圖片二進(jìn)制流保存為文件 FileCopyUtils.copy(request.getInputStream(), new FileOutputStream(uploadFile)); } catch (IOException ioException) { logger.error("圖片保存到文件夾中出錯(cuò)!", ioException); } catch (Exception e) { logger.error("文件沒有復(fù)制到指定的目錄下" ,e); }
此時(shí)后端就能夠獲取前端上傳的圖片了,ios 機(jī)型(iPhone 6s)依然沒問題,安卓上傳png格式的圖片沒有任何問題,但是jpg依然無法上傳。在后端的時(shí)候,打印 request 的 headers,發(fā)現(xiàn)安卓機(jī)型上傳jpg圖片是會(huì)丟失 content-type,值為空。結(jié)合 issues 中的判斷,也許是安卓機(jī)型在壓縮 jpg 格式圖片時(shí)出了問題,先解決再試試看!
第二步:加上androidpatch
根據(jù)官方說明,使用 webuploader.custom.js,其中將 runtime/html5/androidpatch.js 打包了進(jìn)來。
然后在沒有修改任何代碼的情況下,經(jīng)過五個(gè)手機(jī)的測(cè)試,新老機(jī)型:華為榮耀、魅藍(lán)、聯(lián)想等等的測(cè)試,安卓機(jī)可以在微信中隨意上傳圖片了。這是個(gè)大坑??!說明無法上傳 jpg 格式圖片的原因竟是壓縮 jpg 格式圖片的時(shí)候出錯(cuò),導(dǎo)致進(jìn)度條卡死,上傳失敗。
總結(jié)使用心得
按照以上的總結(jié),我想下一次我應(yīng)該能再一次利用這一次的經(jīng)驗(yàn)解決微信上傳圖片的坑了~也懂得從request 的 headers 中尋找 bug 發(fā)生的原因,WebUploader 是個(gè)很優(yōu)秀的開源插件,源碼也寫的很有條理,清晰易讀,雖然我并沒有讀完?,F(xiàn)在閱讀框架源碼是越來越輕松了,加油,下個(gè)目標(biāo)是正在學(xué)習(xí)的 React.js。
以上所述是小編給大家介紹的Android 開發(fā) 使用WebUploader解決安卓微信瀏覽器上傳圖片中遇到的bug,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
- Android使用post方式上傳圖片到服務(wù)器的方法
- Android實(shí)現(xiàn)本地上傳圖片并設(shè)置為圓形頭像
- Android Retrofit 2.0框架上傳圖片解決方案
- Android實(shí)現(xiàn)上傳圖片至java服務(wù)器
- android上傳圖片到PHP的過程詳解
- Android基于OkHttp實(shí)現(xiàn)下載和上傳圖片
- Android 通過Base64上傳圖片到服務(wù)器實(shí)現(xiàn)實(shí)例
- Android異步上傳圖片到PHP服務(wù)器
- Android使用OkHttp上傳圖片的實(shí)例代碼
- Android實(shí)現(xiàn)點(diǎn)擊圖片上傳SQLite數(shù)據(jù)庫(kù)
相關(guān)文章
Android開發(fā)之開關(guān)按鈕控件ToggleButton簡(jiǎn)單用法示例
這篇文章主要介紹了Android開發(fā)之開關(guān)按鈕控件ToggleButton簡(jiǎn)單用法,結(jié)合實(shí)例形式分析了Android開關(guān)按鈕控件ToggleButton的相關(guān)xml布局與調(diào)用操作技巧,需要的朋友可以參考下2017-12-12Android中使用am命令實(shí)現(xiàn)在命令行啟動(dòng)程序詳解
這篇文章主要介紹了Android中使用am命令實(shí)現(xiàn)在命令行啟動(dòng)程序詳解,本文詳細(xì)講解了am命令的語法,然后給出了啟動(dòng)內(nèi)置程序的操作實(shí)例,需要的朋友可以參考下2015-04-04Android編程基于自定義view實(shí)現(xiàn)公章效果示例【附源碼下載】
這篇文章主要介紹了Android編程基于自定義view實(shí)現(xiàn)公章效果,結(jié)合實(shí)例形式分析了Android使用自定義view進(jìn)行圖形繪制的相關(guān)操作技巧,并附帶完整實(shí)例源碼供讀者下載參考,需要的朋友可以參考下2017-11-11Android自定義view仿微信刷新旋轉(zhuǎn)小風(fēng)車
這篇文章主要介紹了Android自定義view仿微信刷新旋轉(zhuǎn)小風(fēng)車,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12Android實(shí)現(xiàn)監(jiān)聽音量的變化
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)監(jiān)聽音量的變化,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-05-05Flutter 實(shí)現(xiàn)虎牙/斗魚 彈幕功能
這篇文章主要介紹了Flutter 實(shí)現(xiàn)虎牙/斗魚 彈幕功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04Android編程檢測(cè)手機(jī)錄音權(quán)限是否打開的方法
這篇文章主要介紹了Android編程檢測(cè)手機(jī)錄音權(quán)限是否打開的方法,涉及Android針對(duì)音頻操作的相關(guān)技巧與注意事項(xiàng),需要的朋友可以參考下2017-11-11Android開發(fā)中使用顏色矩陣改變圖片顏色,透明度及亮度的方法
這篇文章主要介紹了Android開發(fā)中使用顏色矩陣改變圖片顏色,透明度及亮度的方法,涉及Android針對(duì)圖片的讀取、運(yùn)算、設(shè)置等相關(guān)操作技巧,需要的朋友可以參考下2017-10-10