前端根据后端数据生成可显示图像是一个比较常见的功能,比如验证码,动态海报。
后端传数据到前端,前端解析成校可视化验数据。
解析过程:指定数据类型 → 根据相关协议显示。
解析包括两个维度:
1.类型
解析后台数据,首先需要确定,返回数据类型,一般返回类型有 blob, arraybuffer。
2.协议
可视化展示需要指定协议,常用协议有 blob: ,data。
diff xhr.responseType + diff protocol
1.responseType: blob
1.1 URL.createObjectURL(blob);
verificationCode().then(async blob => {
this.url = window.URL.createObjectURL(blob);
}
Object URL 是一种伪协议,也被称为 Blob URL。它允许 Blob 或 File 对象用作图像,下载二进制数据链接等的 URL 源。在浏览器中,我们使用 URL.createObjectURL 方法来创建 Blob URL,该方法接收一个 Blob 对象,并为其创建一个唯一的 URL,其形式为 blob:<origin>/<uuid>,对应的示例如下:
blob:https://example.org/40a5fb5a-d56d-4a33-b4e2-0acf6a8e5f641
浏览器内部为每个通过 URL.createObjectURL 生成的 URL 存储了一个 URL → Blob 映射。因此,此类 URL 较短,但可以访问 Blob。生成的 URL 仅在当前文档打开的状态下才有效。但如果你访问的 Blob URL 不再存在,则会从浏览器中收到 404 错误。
缺点:虽然存储了 URL → Blob 的映射,但 Blob 本身仍驻留在内存中,浏览器无法释放它。映射在文档卸载时自动清除,因此 Blob 对象随后被释放。但是,如果应用程序寿命很长,那不会很快发生。因此,如果我们创建一个 Blob URL,即使不再需要该 Blob,它也会存在内存中。
针对这个问题,我们可以调用 URL.revokeObjectURL(url) 方法,从内部映射中删除引用,从而允许删除 Blob(如果没有其他引用),并释放内存。
1.2 blob协议转data协议
const blobToBase64 = (blob) => {
return new Promise((resolve, reject) => {
const fileReader = new FileReader();
fileReader.onload = e => {
resolve(e.target.result);
};
fileReader.readAsDataURL(blob);
fileReader.onerror = () => {
reject(new Error("文件流异常"));
};
});
}
verificationCode().then(async blob => {
this.url = blobToBase64(blob)
}
base64是 Data URI协议的一种实现,在1998年被确定,具体Data URI详细介绍。
1.3 blob 转 arraybuffer 转 data
verificationCode().then(async blob => {
transformArrayBufferToBase64(response);
}
const async transformArrayBufferToBase64 = (response) => {
response = await this.fileReadAsArrayBuffer(response);
this.url =
"data:image/png;base64," +
btoa(
new Uint8Array(response).reduce(
(data, byte) => data + String.fromCharCode(byte),
""
)
);
}
2.responseType: arraybuffer
2.1 arraybuffer 转 base64
verificationCode().then(blob => {
this.url = "data:image/png;base64," +
btoa(
new Uint8Array(response).reduce(
(data, byte) => data + String.fromCharCode(byte),
""
)
);
}
额外知识点
arraybuffer转Blob
var buffer = new ArrayBuffer(16);
var blob = new Blob([buffer]);
blob转arraybuffer
借助FileReader对象
var blob = new Blob([1,2,3,4,5]);
var reader = new FileReader();
reader.onload = function() {
console.log(this.result);
}
reader.readAsArrayBuffer(blob);
File FileList FileReader关系:
FileReader只能读取 File或者 blob对象,File对象是FileList的子集.
http 如何指定xhr.response的数据类型
有些时候我们希望xhr.response返回的就是我们想要的数据类型。比如:响应返回的数据是纯JSON字符串,但我们期望最终通过xhr.response拿到的直接就是一个 js 对象,我们该怎么实现呢?
有2种方法可以实现,一个是level 1就提供的overrideMimeType()方法,另一个是level 2才提供的xhr.responseType属性。
xhr.overrideMimeType()
overrideMimeType是xhr level 1就有的方法
如果服务器没有指定一个[Content-Type]
头, XMLHttpRequest
默认MIME类型为"text/xml"
. 如果接受的数据不是有效的XML,将会出现格”格式不正确“的错误。你能够通过调用 overrideMimeType()
指定各种类型来避免这种情况。
// Interpret the received data as plain text
req = new XMLHttpRequest();
req.overrideMimeType("text/plain");
req.addEventListener("load", callback, false);
req.open("get", url);
req.send();
再举一个使用场景,我们都知道xhr level 1不支持直接传输blob二进制数据,那如果真要传输 blob 该怎么办呢?当时就是利用overrideMimeType方法来解决这个问题的。
下面是一个获取图片文件的代码示例:
var xhr = new XMLHttpRequest();
//向 server 端获取一张图片
xhr.open('GET', '/path/to/image.png', true);
// 这行是关键!
//将响应数据按照纯文本格式来解析,字符集替换为用户自己定义的字符集
xhr.overrideMimeType('text/plain; charset=x-user-defined');
xhr.onreadystatechange = function(e) {
if (this.readyState == 4 && this.status == 200) {
//通过 responseText 来获取图片文件对应的二进制字符串
var binStr = this.responseText;
//然后自己再想方法将逐个字节还原为二进制数据
for (var i = 0, len = binStr.length; i < len; ++i) {
var c = binStr.charCodeAt(i);
//String.fromCharCode(c & 0xff);
var byte = c & 0xff;
}
}
};
xhr.send();
代码示例中xhr请求的是一张图片,通过将 response 的 content-type 改为'text/plain; charset=x-user-defined',使得 xhr 以纯文本格式来解析接收到的blob 数据,最终用户通过this.responseText拿到的就是图片文件对应的二进制字符串,最后再将其转换为 blob 数据。
xhr.responseType
下面是同样是获取一张图片的代码示例,相比xhr.overrideMimeType,用xhr.response来实现简单得多。
var xhr = new XMLHttpRequest();
xhr.open('GET', '/path/to/image.png', true);
//可以将`xhr.responseType`设置为`"blob"`也可以设置为`" arrayBuffer"`
//xhr.responseType = 'arrayBuffer';
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this.status == 200) {
var blob = this.response;
...
}
};
xhr.send();
简单来说,responseType就是把文本转换成 二进制了,二进制和文本怎么转换呢,请看下文分解
参考资源
玩转前端二进制
前端二进制学习
你真的会使用XMLHttpRequest吗
JS字符串与二进制的相互转化实例代码详解
玩转图片流Base64编码原理与应用
Data URI详细介绍
细说 Data URI
网友评论