Skip to content
On this page

2022-10-fetch获取图片的md5值

1. 需求场景

拿到一个图片的MD5值。

2. 思路

http请求图片地址,拿到二进制数据,再计算md5值。

3. 实现方式

3.1 img标签

export const md5Image = (imagePath: string) => {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.setAttribute('crossOrigin', 'Anonymous');
    img.src = imagePath;
    img.onload = (e) => {
      const canvas = document.createElement('canvas');
      const context = canvas.getContext('2d');
      const w = img.width;
      const h = img.height;
      canvas.width = w;
      canvas.height = h;
      context && context.drawImage(img, 0, 0, w, h);
      const type = 'image/jpg';
      // 将canvas元素中的图像转变为DataURL
      const dataurl = canvas.toDataURL(type);
      // 抽取DataURL中的数据部分,并进行Base64解码
      const bin = atob(dataurl.split(',')[1]);
      // 创建空的Uint8Array
      const buffer = new Uint8Array(bin.length);
      // 将图像数据逐字节放入Uint8Array中
      // eslint-disable-next-line no-plusplus
      for (let i = 0; i < bin.length; i++) {
        buffer[i] = bin.charCodeAt(i);
      }
      // 利用Uint8Array创建Blob对象
      const blob = new Blob([buffer.buffer], { type });
      const fileReader = new FileReader();
      fileReader.readAsBinaryString(blob);
      // 提取成功
      fileReader.onload = (evt: any) => {
        if (evt.target.readyState === FileReader.DONE) {
          // 二进制数据结果
          const imgFlag = evt.target.result;
          // 进行md5加密
          const spark = new SparkMD5();
          spark.appendBinary(imgFlag);
          resolve(spark.end());
        }
      };
    };
  });
};

这种方式因为图片的二进制流是从canvas中拿出来的,可能跟真实的图片有误差,导致不准确。

3.2 xmlhttprequest

export const md5ImageByXMLRequest = (imagePath: string) => {
  return new Promise((resolve, reject) => {
    const xmlhttp = new XMLHttpRequest();
    xmlhttp.open('GET', imagePath, true);
    xmlhttp.responseType = 'blob';
    xmlhttp.setRequestHeader('Access-Control-Allow-Origin', '*');
    xmlhttp.onerror = (e) => {
      // console.error('md5-image', e);
      reject();
    };
    xmlhttp.onload = function () {
      if (this.status === 200) {
        const blob = this.response;
        const fileReader = new FileReader();
        fileReader.readAsBinaryString(blob);
        // 提取成功
        fileReader.onload = (evt: any) => {
          if (evt.target.readyState === FileReader.DONE) {
            // 二进制数据结果
            const imgFlag = evt.target.result;
            // 进行md5加密
            const spark = new SparkMD5();
            spark.appendBinary(imgFlag);
            resolve(spark.end());
          }
        };
        fileReader.onerror = (e) => {
          console.error(e);
          reject();
        };
      }
    };
    xmlhttp.send();
  });
};

这种写法没问题,但和fretch相比不简洁。

3.3 fetch

export const md5ImageByFetch = (imagePath: string) => {
  return new Promise((resolve, reject) => {
    fetch(imagePath).then((res: any) => res.blob()).then((blob: any) => {
      const fileReader = new FileReader();
      fileReader.readAsBinaryString(blob);
      // 提取成功
      fileReader.onload = (evt: any) => {
        if (evt.target.readyState === FileReader.DONE) {
          // 二进制数据结果
          const imgFlag = evt.target.result;
          // 进行md5加密
          const spark = new SparkMD5();
          spark.appendBinary(imgFlag);
          resolve(spark.end());
        }
      };
      fileReader.onerror = (e) => {
        console.error(e);
        reject();
      };
    });
  });
};

4. fetch的response

上面的方法用到了response的blob方法。response有很多的属性和方法如下:

  • Response.ok: 返回一个布尔值,表示请求是否成功,true对应 HTTP 请求的状态码 200 到 299,false对应其他的状态码。
  • Response.status:返回一个数字,表示 HTTP 回应的状态码(例如200,表示成功请求)。
  • Response.statusText:返回一个字符串,表示 HTTP 回应的状态信息(例如请求成功以后,服务器返回"OK")。
  • Response.url: 返回请求的 URL。如果 URL 存在跳转,该属性返回的是最终 URL。
  • Response.type: 返回请求的类型。可能的值如下:
basic:普通请求,即同源请求。
cors:跨域请求。
error:网络错误,主要用于 Service Worker。
opaque:如果fetch()请求的type属性设为no-cors,就会返回这个值,详见请求部分。表示发出的是简单的跨域请求,类似<form>表单的那种跨域请求。
opaqueredirect:如果fetch()请求的redirect属性设为manual,就会返回这个值,详见请求部分。
  • Response.redirected: 返回一个布尔值,表示请求是否发生过跳转。
  • Response.headers: 对应 HTTP 回应的所有标头,其属性有:
Headers.get():根据指定的键名,返回键值。
Headers.has(): 返回一个布尔值,表示是否包含某个标头。
Headers.set():将指定的键名设置为新的键值,如果该键名不存在则会添加。
Headers.append():添加标头。
Headers.delete():删除标头。
Headers.keys():返回一个遍历器,可以依次遍历所有键名。
Headers.values():返回一个遍历器,可以依次遍历所有键值。
Headers.entries():返回一个遍历器,可以依次遍历所有键值对([key, value])。
Headers.forEach():依次遍历标头,每个标头都会执行一次参数函数。
  • response.text():得到文本字符串。
  • response.json():得到 JSON 对象。
  • response.blob():得到二进制 Blob 对象。
  • response.formData():得到 FormData 表单对象。
  • response.arrayBuffer():得到二进制 ArrayBuffer 对象。

5. 参考文章

Released under the MIT License.