前端JS中使用XMLHttpRequest 2上傳圖片到服務器,PC端和大部分手機上都正常,但在少部分安卓手機上上傳失敗,服務器上查看圖片,顯示字節數為0。下面是上傳圖片的核心代碼:
HTML
<input type="file" id="choose" capture="camera" accept="image/*"> JavaScriptvar filechooser = document.getElementById("choose");filechooser.onchange = function () {var _this = $(this);if (!this.files.length) return;var files = Array.prototype.slice.call(this.files);if (files.length > 1) {alert("一次只能上傳1張圖片");return;}files.forEach(function (file, i) {if (!///(?:jpeg|png|gif)/i.test(file.type)) return;var reader = new FileReader();reader.onload = function () {var result = this.result;upload(result, file.type);};reader.readAsDataURL(file);});};function upload(basestr, type){var xhr = new XMLHttpRequest();var text = window.atob(basestr.split(",")[1]);var buffer = new Uint8Array(text.length);var pecent = 0;for (var i = 0; i < text.length; i++) {buffer[i] = text.charCodeAt(i);}var blob = getBlob(buffer, type);var formdata = new FormData();formdata.append('imagefile', blob);xhr.open('post', '/uploadtest');xhr.onreadystatechange = function () {if (xhr.readyState == 4 && xhr.status == 200) {var jsonData = JSON.parse(xhr.responseText);console.log(jsonData);}};//利用progress事件顯示數據發送進度xhr.upload.addEventListener('progress', function (e) {pecent = ~~(100 * e.loaded / e.total) / 2;// 利用pecent來顯示上傳進度}, false);xhr.send(formdata);}function getBlob(buffer, format){var Builder = window.WebKitBlobBuilder || window.MozBlobBuilder;if(Builder){var builder = new Builder();builder.append(buffer);return builder.getBlob(format);} else {return new window.Blob([ buffer ], {type: format});}} 上述代碼使用FormData來實現表單數據提交。FormData是一種針對XHR2設計的新型數據類型,使用它我們可以很方便地實時以JavaScript創建HTML <Form>,然后通過AJAX提交該表單。在上述代碼中,提交的表單中的字段名為imagefile,值是blob,這是一個通過getBlob函數構造并返回的文件Blob。通過該方法上傳文件簡單直觀。
然后我們在服務端接收并保存圖片,并返回已上傳的圖片的信息。
下面是Node.js代碼的示例:
var Q = require('q');var fs = require('fs');var path = require('path');var formidable = require('formidable');var moment = require('moment');var imageUpload = function (){ };imageUpload.prototype.useFormParseCallback = function(req){var deferred = Q.defer();var form = new formidable.IncomingForm();form.parse(req, deferred.makeNodeResolver());return deferred.promise;};imageUpload.prototype.uploadImageTest = function(req){var pathName = 'uploadImgs/dealInfo/';var uploadPath = path.join(__dirname, '../../public/', pathName);return this.useFormParseCallback(req).then(function(files){var file = files[1].imagefile;var fileType = files[1].imagefile.type.split('/')[1];var newFileName = 'upload_' + moment().format('x') + Math.random().toString().substr(2, 10) + '.' + fileType;var readStream = fs.createReadStream(file.path);var writeStream = fs.createWriteStream(uploadPath + newFileName);var deferred = Q.defer();readStream.pipe(writeStream);readStream.on('end', deferred.makeNodeResolver());return deferred.promise.then(function() {fs.unlinkSync(file.path);return {fileName: newFileName,filePath: '/' + pathName + newFileName,fileSize: file.size/1024 > 1024 ? (~~(10*file.size/1024/1024))/10 + "MB" : ~~(file.size/1024) + "KB"};});});};module.exports = imageUpload; 我們使用formidable這個包來接收上傳文件的數據,然后將文件保存到/public/uploadImgs/dealInfo目錄下(假定已在express中將public設置為static的根目錄),并將圖片按照指定的規則重命名,以保證上傳圖片不會因為名稱相同而被覆蓋。另外,代碼中使用Q來避免直接使用回調函數,以更好地對函數功能進行分離。
上面的代碼在PC端瀏覽器以及大部分主流移動設備上都能正常工作,但是少部分Android設備上卻會出現上傳的圖片字節數為0的情況。具體的原因大家可以看下面幾個網頁中的描述:
就是說這個是Android的一個bug!
那如何解決呢?
其實從上面給出的頁面中可以找到答案,就是我們得換一種文件上傳方式。在XHR2中,除了以Blob的方式上傳文件外,還可以ArrayBuffer的方式上傳文件。
下面是修改之后的前端JavaScript代碼:
var filechooser = document.getElementById("choose");filechooser.onchange = function () {var _this = $(this);if (!this.files.length) return;var files = Array.prototype.slice.call(this.files);if (files.length > 1) {alert("一次只能上傳1張圖片");return;}files.forEach(function (file, i) {if (!///(?:jpeg|png|gif)/i.test(file.type)) return;var reader = new FileReader();reader.onload = function () {var result = this.result;upload(result, file.type);};reader.readAsDataURL(file);});};function upload(basestr, type){var xhr = new XMLHttpRequest();var text = window.atob(basestr.split(",")[1]);var buffer = new Uint8Array(text.length);var pecent = 0;for (var i = 0; i < text.length; i++) {buffer[i] = text.charCodeAt(i);}xhr.open('post', '/uploadtest?filetype=' + type.split('/')[1]);xhr.setRequestHeader('Content-Type', 'application/octet-stream');xhr.onreadystatechange = function () {if (xhr.readyState == 4 && xhr.status == 200) {var jsonData = JSON.parse(xhr.responseText);console.log(jsonData);}};//利用progress事件顯示數據發送進度xhr.upload.addEventListener('progress', function (e) {pecent = ~~(100 * e.loaded / e.total) / 2;// 利用pecent來顯示上傳進度}, false);xhr.send(buffer.buffer); // 以ArrayBuffer的方式上傳圖片} 我將有變化的地方加了高亮顯示。以ArrayBuffer方式上傳圖片必須添加'application/octet-stream'的RequestHeader,否則服務器無法響應請求。另外,通過這種方式上傳圖片我們也無法從表單數據中獲取到文件類型,可以將文件類型以query的方式傳到服務器,然后服務器根據文件類型來生成對應的文件,以下是經過少量修改之后的服務器代碼:
imageUpload.prototype.uploadImageTest = function(req){var pathName = 'uploadImgs/dealInfo/';var uploadPath = path.join(__dirname, '../../public/', pathName);return this.useFormParseCallback(req).then(function(files){var file = files[1].file;var fileType = req.query.filetype ? ('.' + req.query.filetype) : '.png';var newFileName = 'upload_' + moment().format('x') + Math.random().toString().substr(2, 10) + '.' + fileType;var readStream = fs.createReadStream(file.path);var writeStream = fs.createWriteStream(uploadPath + newFileName);var deferred = Q.defer();readStream.pipe(writeStream);readStream.on('end', deferred.makeNodeResolver());return deferred.promise.then(function() {fs.unlinkSync(file.path);return {fileName: newFileName,filePath: '/' + pathName + newFileName,fileSize: file.size/1024 > 1024 ? (~~(10*file.size/1024/1024))/10 + "MB" : ~~(file.size/1024) + "KB"};});});}; 修改之后的代碼可以支持Android手機,包括微信瀏覽器。注意不是所有的Android手機都會存在該問題,如果你發現在Andriod手機上無法上傳圖片,尤其是在微信瀏覽器中,則可以嘗試下上面的方法。
以上所述是小編給大家介紹的關于安卓手機微信瀏覽器中使用XMLHttpRequest 2上傳圖片顯示字節數為0的解決辦法,希望對大家有所幫助!
新聞熱點
疑難解答