Вы знаете, как внешний интерфейс обрабатывает изображения?

JavaScript

предисловие

Мы, фронтенд-инженеры, неизбежно имеем дело с изображениями каждый день. Разработчики внешнего интерфейса, работающие над основными платформами электронной коммерции, могут чувствовать себя более очевидными.

Ниже приведены ямы, на которые я наступал раньше, когда имел дело с изображениями, и я поделюсь своим опытом с вами.

1. Репродукция сценария

При использовании Postman для запроса интерфейса возвращается это изображение (двоичное)

postman

При просмотре сети в хроме тоже возвращается это изображение (бинарное).

network

Однако при печати отладки возвращаются искаженные символы.

debug

Очевидно, тип данных был изменен. Если подумать, единственное место, где можно изменить тип данных, — это axios.

Я пошел посмотреть документацию axios, которая описана так

// `responseType` indicates the type of data that the server will respond with
// options are 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
responseType: 'json', // default

Таким образом, искаженные символы появляются, потому что:Axios по умолчанию возвращает текстовую форму json, а данные двоичного изображения преобразуются в текстовую форму json.

Как только причина найдена, решение легко.В axios типом возвращаемых данных по умолчанию для responseType является json, измените его на возвращаемый тип данных blob.

export function miniprogramQrcode (params) {
  return axios.post(
    env.MI_URL + '/XXXX/XXX/XXXX',
    params,
    // 将responseType的默认json改为blob
    {
    responseType: 'blob',
    emulateJSON: true
  }).then(res => {
    if (res.data) {
      return Promise.resolve(res.data)
    } else {
      throw res
    }
  }).catch(err => {
    return Promise.reject(err)
  })
}

Следующий вопрос: как работать с объектом blob и отображать его на странице интерфейса?

код показывает, как показано ниже:

createMiniQrcode (blob) {
  let img = document.createElement('img')
  img.onload = function (e) {
    // 元素的onload 事件触发后将销毁URL对象, 释放内存。
    window.URL.revokeObjectURL(img.src)
  }
  // 浏览器允许使用URL.createObjectURL()方法,针对 Blob 对象生成一个临时 URL。
  // 这个 URL 以blob://开头,表明对应一个 Blob 对象。
  img.src = window.URL.createObjectURL(blob)
  document.querySelector('.imgQrCode').appendChild(img)
}

Вы думали, что это закончилось? Нет, нет, нет. Знать, как решить проблему, недостаточно.Думайте дивергентно через внешность.

2. Дивергентное мышление

Вообще говоря, есть два способа хранения изображений в бэкенде:

其一:可以将图片以独立文件的形式存储在服务器的指定文件夹中,再将路径存入数据库字段中;
其二:将图片转换成二进制流,直接存储到数据库的 Image 类型字段中.

Для первого метода хранения мы можем легко отобразить его, напрямую назначив путь хранения атрибуту src во внешнем интерфейсе.

Для второго метода хранения наш внешний интерфейс должен передать свой двоичный поток объекту BLOB-объекта, а затем сгенерировать временный URL-адрес через API BLOB-объектов и назначить его атрибуту src для отображения.

Оба метода хранения имеют соответствующие решения, которые, кажется, идеально решили проблему отображения изображения. Однако наши бизнес-сценарии разнообразны и изменчивы. Иногда мы также сталкиваемся с такими сценариями, например, после перетаскивания и загрузки изображения вам автоматически возвращается объект Blob, но, к сожалению, вы обнаруживаете, что использовали интерфейс стороннего сервиса только для получения данных в формате base64. Хочешь плакать без слез?

Итак, можно ли преобразовать три представления изображений, url, base64 и blob, чтобы удовлетворить потребности? Ответ положительный. следующим образом:

流程图

1. ссылка на base64

URL для пакета метода Base64

// 原理: 利用canvas.toDataURL的API转化成base64

urlToBase64(url) {
  return new Promise ((resolve,reject) => {
      let image = new Image();
      image.onload = function() {
        let canvas = document.createElement('canvas');
        canvas.width = this.naturalWidth;
        canvas.height = this.naturalHeight;
        // 将图片插入画布并开始绘制
        canvas.getContext('2d').drawImage(image, 0, 0);
        // result
        let result = canvas.toDataURL('image/png')
        resolve(result);
      };
      // CORS 策略,会存在跨域问题https://stackoverflow.com/questions/20424279/canvas-todataurl-securityerror
      image.setAttribute("crossOrigin",'Anonymous');
      image.src = url;
      // 图片加载失败的错误处理
      image.onerror = () => {
        reject(new Error('图片流异常'));
    };
}

Вы можете назвать это:

let imgUrL = `http://XXX.jpg`

this.getDataUri(imgUrL).then(res => {
  // 转化后的base64图片地址
  console.log('base64', res)
})

2. base64 в блоб

Метод инкапсуляции base64 в blob

// 原理:利用URL.createObjectURL为blob对象创建临时的URL

base64ToBlob ({b64data = '', contentType = '', sliceSize = 512} = {}) {
    return new Promise((resolve, reject) => {
      // 使用 atob() 方法将数据解码
      let byteCharacters = atob(b64data);
      let byteArrays = [];
      for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
        let slice = byteCharacters.slice(offset, offset + sliceSize);
        let byteNumbers = [];
        for (let i = 0; i < slice.length; i++) {
            byteNumbers.push(slice.charCodeAt(i));
        }
        // 8 位无符号整数值的类型化数组。内容将初始化为 0。
        // 如果无法分配请求数目的字节,则将引发异常。
        byteArrays.push(new Uint8Array(byteNumbers));
      }
      let result = new Blob(byteArrays, {
        type: contentType
      })
      result = Object.assign(result,{
        // jartto: 这里一定要处理一下 URL.createObjectURL
        preview: URL.createObjectURL(result),
        name: `图片示例.png`
      });
      resolve(result)
    })
 }

Вы можете назвать это так:

let base64 = base64.split(',')[1]

this.base64ToBlob({b64data: base64, contentType: 'image/png'}).then(res => {
    // 转后后的blob对象
    console.log('blob', res)
})



3. блоб в base64

Метод инкапсуляции блоба в base64

// 原理:利用fileReader的readAsDataURL,将blob转为base64

blobToBase64(blob) {
    return new Promise((resolve, reject) => {
      const fileReader = new FileReader();
      fileReader.onload = (e) => {
        resolve(e.target.result);
      };
      // readAsDataURL
      fileReader.readAsDataURL(blob);
      fileReader.onerror = () => {
        reject(new Error('文件流异常'));
      };
    });
}

Вы можете назвать это так:

this.blobToBase64(blob).then(res => {
    // 转化后的base64
    console.log('base64', res)
})

Больше ссылок на base64, base64 и blob демонстрации взаимного преобразования, следите за обновлениями здесь, заинтересованные могут ткнутьпортал

ps: вышеописанный метод предназначен дляИграйте с потоковой передачей изображенийоптимизация, спасибо оригинальному автору.

В-третьих, краткое изложение методов обработки изображений.

1. Как хранить изображения в бэкенде

Как мы упоминали ранее, есть два способа хранения изображений в бэкенде.Давайте рассмотрим: во-первых, изображения могут храниться как независимые файлы в указанной папке сервера, а затем путь может храниться в поле базы данных;второй : преобразовать изображение в бинарный поток и сохранить его непосредственно в поле Тип изображения базы данных;

Итак, какой из этих двух способов хранения лучше?

Насколько я понимаю, в интернет-среде важен большой объем трафика, скорость базы данных и производительность. Как правило, практика хранения изображений в базе данных меньше, а больше - хранить путь к изображению в базе данных.При отображении изображения вам нужно только подключить путь к диску и загрузить изображение. Потому что картина принадлежит большому полю. Картинка может быть от 1м до нескольких метров. Такие большие полевые данные увеличивают нагрузку на базу данных и замедляют ее работу. Важно в случае больших одновременных доступов. Это опыт. Посетив анализ настройки производительности базы данных, проведенный dba, можно получить ответ: то есть изображения не должны храниться в базе данных.

Поэтому, если back-end брат вашей компании часто хранит изображение в базе данных в бинарном виде, а потом возвращает его вам на стыковку, вы должны знать, как его дуить (funny face).

Подробнее о том, как изображения или файлы хранятся в базе данныхПожалуйста, нажмите здесь

2. Как отображаются фронтальные картинки

Для передней части: Существует три способа отображения изображений во внешнем интерфейсе: url, base64, blob.

Какой из трех методов отображения более элегантен?

URL: Вообще говоря, рекомендуется использовать URL для отображения изображений. Если поле, переданное из бэкэнда, является путем к изображению.

base64: Если картинка большая и цветовой уровень картинки насыщенный, этот способ не подходит, так как строка в кодировке Base64 очень большая, что значительно увеличит HTML-страницу и повлияет на скорость загрузки. Если изображение похоже на загрузку или строку таблицы, размер крайне мал, но занимает один HTTP-запрос и будет использоваться во многих местах. Он очень подходит для оптимизации технологии "base64: URL-изображение"! Подробная демонстрационная презентация Чжан Синьсюй,Пожалуйста, нажмите здесь.

blob: когда серверная часть возвращает определенный двоичный поток изображения, как я сказал в воспроизведении сцены в первой части, внешний интерфейс использует контейнер больших двоичных объектов для его получения. Изображение лучше отображать в блобе.

4. Чувства

Давать, записывать, подводить итоги. Я буду записывать и разбирать проблемы, возникающие в проекте по крупицам. Я считаю, что это разрозненные ветки и листья, которые с увеличением опыта проекта вырастут в высокое дерево.

Мнения в этой статье ограничены моим текущим техническим уровнем, и неизбежно будут ошибки Добро пожаловать, чтобы оставить сообщение в области комментариев для обмена и исправления.

По мере улучшения технического уровня статья будет время от времени дорабатываться и оптимизироваться~ Вы можете связаться со мной следующими способами.

обо мне

微信公众号二维码

Обзорная статья:

Использованная литература: