2021-11-06-⛵︎数字到图像(1) 不同数据类型协议转图片

前端根据后端数据生成可显示图像是一个比较常见的功能,比如验证码,动态海报。
后端传数据到前端,前端解析成校可视化验数据。

解析过程:指定数据类型根据相关协议显示

解析包括两个维度:

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:/,对应的示例如下:

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

你可能感兴趣的:(2021-11-06-⛵︎数字到图像(1) 不同数据类型协议转图片)