深入理解xhr的responseType中blob和arrayBuffer
来源:互联网 发布:无主之地2怎么连接网络 编辑:程序博客网 时间:2024/06/08 16:13
最近有个需求,服务器端下载视频,存储到本地,然后再播放,下载存储后播放不了。debug后发现是responseType未正确设置。
一般的xhr请求
let url = window.URL || window.webkitURL; let xhr = new XMLHttpRequest(); xhr.open(method, url, [,async=true,]); xhr.ontimeout = ()=>{}; xhr.onreadystatechange=()=>{ if(xhr.readystate === 4) { if(xhr.status =200) { let res = xhr.responseText; let blob = new Blob([res], {type: 'video/mpeg4'}); .... .... videoEle.src = url.createObjectURL(blob); }; } };
上面代码处理一般的xhr请求足够满足,即返回类型为DOMString的,但是处理视频下载并且存储后播放就会有问题,上面代码处理异步视频下载有两个bug,如果你都知道,就不需要往下看了^_^
再次认识responseType
设置该值能够改变响应类型(关键这句话)。就是告诉服务器你期望的响应格式。
responseType值的类型可为如下
video后台为设置的content-type为application/octet-stream,表示二进制流。。当时就被这货坑了一下,以为返回的数据能够够Blob构造函数接收,并正确显示。
Blob对象
Blob也是比较有意思,mdn上的解释是Blob对象表示不可变的类似文件对象的原始数据。Blob表示不一定是JavaScript原生形式的数据。
^_^其实就是英文Binary large Object,mysql有此类型数据结构
let blog = new Blob(arrya, options);
Blob() 构造函数返回一个新的 Blob 对象。
array 是一个由ArrayBuffer, ArrayBufferView, Blob, DOMString 等对象构成的 Array ,或者其他类似对象的混合体,它将会被放进 Blob。DOMStrings会被编码为UTF-8。
options 是一个可选的BlobPropertyBag字典,它可能会指定如下两个属性:
type,默认值为 “”,它代表了将会被放入到blob中的数组内容的MIME类型。
ArrayBuffer涉及面比较广,我的理解是ArrayBuffer代表内存之中的一段二进制数据,一旦生成不能再改。可以通过视图(TypedArray和DataView)进行操作。
TypedArray数组只是一层视图,本身不储存数据,它的数据都储存在底层的ArrayBuffer对象之中, 所以通过同一个arraybuffer生成的TypedArray共享内存数据。
nodejs中的buffer是对Uint8Array的实现。详细可参考另外一篇我写的文章
正确的video流打开方式
还有一点xhr.responseText的类型为DOMString,只有当responseType为DOMString时才有正确数据,其他类型获取响应实体用xhr.response。因为一般我们都是获取json字符串,此处也需要注意下。
so正确的代码如下:
let url = window.URL || window.webkitURL; let xhr = new XMLHttpRequest(); xhr.open(method, url, [,async=true,]); xhr.responseType = 'blob' ; //arraybuffer也可以 xhr.ontimeout = ()=>{}; xhr.onreadystatechange=()=>{ if(xhr.readystate === 4) { if(xhr.status =200) { let res = xhr.response; //不是responseText。 let blob = new Blob([res], {type: 'video/mpeg4'}); .... .... videoEle.src = url.createObjectURL(blob); //Videos on Android do not play when the src is set as a blob via create URL, 在移动端有兼容问题 }; } };
后面的内容与本文无关,纯作记录。
后续
项目中的video都存储在移动设备中,如果都放在blob中,会造成内存的大量占用,因是cordova的webapp形式,故采用插件cordova-plugin-file,
相关写文件代码如下
function writeSystemFile(videoBlob, isAppend) { let self = this; window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) { //console.log('openFsObj', fs); //console.log('open file name: ', fs.name); fs.root.getFile(self._storeVideoName, { create: true, exclusive: false },function (fileEntry) { // var dataObj = new Blob([videoData], { type: 'text/plain' }); self.writeFile(fileEntry, videoBlob, isAppend); }, function(e) { console.log('onErrorCreateFile, error:', e); }); }, function(e) { console.log('onErrorLoadFs, error:', e); }); } function writeFile(fileEntry, dataObj, isAppend) { // let self = this; fileEntry.createWriter(function (fileWriter) { fileWriter.onwriteend = function() { console.log('Successful file write...'); //console.log('fileWriterEnd.length:', fileWriter.length); }; fileWriter.onerror = function (e) { console.log('Failed file write: ' + e.toString()); }; if(isAppend) { //表示是否追加文件 try { console.log('fileWriter.length:', fileWriter.length); fileWriter.seek(fileWriter.length); } catch(e) { console.log('file doesn`t exist:', e.toString()); } } //console.log('fileWriterStart.length:', fileWriter.length); fileWriter.write(dataObj); }); }
读文件代码
function readSystemFile() { let self = this; console.log('readSystemFile self._storeVideoName:', self._storeVideoName); window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) { fs.root.getFile(self._storeVideoName, { create: true, exclusive: false },function (fileEntry) { self.readFile(fileEntry); }, self.onErrorCreateFile); }, function (error) { console.log('onErrorLoadFs, error:', error); }); } function readFile(fileEntry) { let self = this; fileEntry.file(function (file) { var reader = new FileReader(); reader.onloadend = function() { if(this.result === null) { console.log('readFile unexpected this.result == null'); return; } console.log(typeof this.result); console.log('Successful file read length: ', this.result.length); // var blob = new Blob([new Uint8Array(this.result)], { type: "video/mpeg4" }); console.log('Successful file read: ', this.result); }; // reader.readAsText(file); reader.readAsArrayBuffer(file); // reader.readAsBinaryString(file); }, self.onErrorReadFile); }onErrorReadFile() { console.log('Failed file read: '); }
因安卓和ios下文件的存储路径不一样,故需要做一个判断,文件的存储目录
function getDirectory() { let isIOS =/(iPad|iPhone|iPod)/g.test(navigator.userAgent); if(isIOS) { return cordova.file.documentsDirectory; }else { return cordova.file.dataDirectory + 'files/'; }}
- 深入理解xhr的responseType中blob和arrayBuffer
- scala 中Array 和 ArrayBuffer的 区别
- 理解DOMString、Document、FormData、Blob、File、ArrayBuffer数据类型
- 理解DOMString、Document、FormData、Blob、File、ArrayBuffer数据类型
- 理解DOMString、Document、FormData、Blob、File、ArrayBuffer数据类型
- 【javascript】arrayBuffer对象的理解
- 深入理解ajax系列之一-XHR对象
- TypeArray、ArrayBuffer、Blob、File、DataURL、canvas的相互转换
- 深入理解ajax系列第一篇——XHR对象
- JavaScript中的ArrayBuffer 理解
- 关于Blob的理解
- 深入理解deep learning之caffe BLOB
- Oracle中Blob和Clob的作用
- Oracle中Blob和Clob的作用
- Oracle中Blob和Clob的作用?
- oracle中BLOB和CLOB的区别
- XHR的常用属性 和 方法
- web开发中Array与ArrayBuffer的区别
- SpringMVC级联获取前台数据
- 登录页面的密码的显示与隐藏
- Modbus 史上最全实例资料汇总
- Python自学基础 判断与循环
- 渗透测试攻击推荐之Burp Suite 从入门到放弃……
- 深入理解xhr的responseType中blob和arrayBuffer
- ubuntu安装迅雷
- android搭建开发环境 ---- gradle wrapper出现问题
- Opencv HighGUI函数_窗口
- 关于如何在WPS中生成附图索引
- 网易2017年校招题
- 51Nod1674[区间的价值 V2]--分块
- 第一篇博客
- SQL基础语句【转帖】