美文网首页
2021-11-06-⛵︎数字到图像(1) 不同数据类型协议转

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

作者: 沐深 | 来源:发表于2021-11-07 22:44 被阅读0次

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

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

    解析包括两个维度:

    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

    相关文章

      网友评论

          本文标题:2021-11-06-⛵︎数字到图像(1) 不同数据类型协议转

          本文链接:https://www.haomeiwen.com/subject/zayyzltx.html