- PVSM.RU - https://www.pvsm.ru -
Доброго времени суток.
Разбор полетов провожу на Reactjs (сторона клиента) и Nodejs (сторона сервера).
Недавно в моем маленьком проекте встал вопрос, как легко и просто можно обмениваться изображениями по типу клиент — сервер.
Сегодня мы научимся отправлять бинарные данные (конкретно изображения ) со стороны клиента и обрабатывать их на сервере. Добро пожаловать в под кат.
Если ваше web-приложение — это соц.сеть или мессенджер или что-то подобное, то вам непременно придется работать с бинарными данными, в большинстве случаев — это обработка изображений. Об этом и пойдет речь.
Чтобы иметь общее представление, я буду толковать последовательно.
Это число, которое записывается с помощью двух символов: единиц и нулей.
Простым языком — это 2 (основание) в степени n (количество разрядов), например число 10001 имеет 5 разрядов:
4 разряд = 1; 2^4 = 16;
3 разряд = 0;
2 разряд = 0;
1 разряд = 0;
0 разряд = 1; 2^0 = 1;
1-true — производим расчет;
0-false — не производим расчет;
В итоге получаем 16 + 1 = 17;
Обратной операцией компьютер представляет данные в двоичном виде.
const num = 17; // десятичное число
const binNum = num.toString(2); // преобразование в двоичный вид
const initNum = parseInt(binNum, 2); // обратная операция
Десятичная система счисления — это число, которое записывается с помощью 10 символов, от 0 — 9. Мы используем их повседневно.
Дело в том, что компьютер живет своим представлением информации. Если мы пишем на родном языке или считаем в десятичной системе счисления, то для компьютера все это двоичное представление. Вы спросите: “Что значит двоичное представление?”. Как говорила моя учительница английского, “как слышится, так и пишется”. Компьютер представляет файлы, содержащие текст или иное, или какие-либо вычисления в двоичную систему счисления — это и есть двоичное представление. Языком машины число «17» является — 10001.
Возникает вопрос. Понятно с числами, но как же текст? Как машина будет преобразовывать текст в двоичный вид? Все просто. Для этого существуют кодировки типа ASCII или Unicode. Это простая таблица ( кодовая страница [2] ), где имеется сопоставление нашему символу число, например символ “S” — это число 53 по таблице ASCII, далее компьютер представит число 53 в двоичном виде — 110101.
Что касаемо Unicode — это мощный стандарт, включающий в себя кодировку UTF-8, которая имеет большой спрос в web-пространстве и unix подобных системах. Принцип работы общий.
Бит — это единица измерения информации компьютером. А мы уже знаем как компьютер представляет информацию. Да! Вы правы. Один бит равен 1 или 0. Для компьютера 1 или 0 — это что-то вроде транзистора, true или false. Теперь понять что такое байт совсем не трудно — это 8 битов, его еще называют октет ( типа состоит из 8 ).
Переходим к “hex” формату. Мы говорили о двоичной системе счисления, десятичной системе, помимо прочего существует и шестнадцатиричная система счисления, верстальщики поймут о чем я. Это число, которое записывается с помощью 16 символов, от 0 — 9 и от a-f. Навивается вопрос: “Зачем так все усложнять?”. Так как единицей памяти является 8-битный байт, все же значение его удобнее записывать двумя шестнадцатиричными цифрами. Также в стандарте Юникода номер символа принято записывать в шестнадцатиричном виде, используя не менее 4 цифр.
Данный формат работает следующим образом: в случае с 8 битным байтом, он делит 8 битов по полам, то есть 10101011 — 1010 | 1011, после преобразует каждую часть соответственно. 1010 — a, 1011 — b;
const num = 196; // десятичное число
const hexNum = num.toString(16); // преобразование в hex вид
const initNum = parseInt(hexNum, 16); // преобразование в десятичный вид - обратная операция
Переходим к следующему пункту, его еще называют бинарным файлом — это массив байтов. Почему двоичный? Байты состоят из битов, то есть символов двоичной системы счисления, отсюда и название двоичный. Под категорию двоичный файл подходят абсолютно все файлы, то есть файлы содержащие текст, изображения — все это двоичные файлы, отсюда двоичные данные, отсюда бинарные данные.
Нередко бинарные данные выводятся символами кодовой страницы ASCII, а также в формате hex, в частности изображения. Приведу пример. У нас есть следующее изображение:
Его частичная визуализация представляется в виде hex-agent-smith [12]
ArrayBuffer — объект для работы с бинарными данными на javascript. Фиксирует длину памяти для работы с бинарником. Например: new ArrayBuffer(256) — создаст массивоподобный объект размером в 256 байт, не больше — не меньше. На каждый байт приходится конкретная информация. ArrayBuffer не является массивом и методы массива к нему не применимы. Вы зададите вопрос, как же его использовать? Объект Uint8Array дает представление ArrayBuffer в беззнаковое 8-битное число, то есть от 0 — 255.
FileReader? Это конструктор по созданию следующего:
<input type="file">
Теперь рассмотрим прекрасный пример [13], демонстрирующий обработку изображения:
import React, {useState, useRef, useCallback} from 'react';
import axios from 'axios';
export const UPLOAD_AVATAR = 'http://localhost:8080/api/upload_avatar';
function App() {
// определим изменяемый ref для объекта FileReader
const fileRef = useRef(null);
const [ loading, setLoading ] = useState(false);
const handleSubmit = useCallback( event => {
event.preventDefault();
const fetchData = async (uint8Array) => {
try {
const response = await axios({
method: 'post',
url: UPLOAD_AVATAR,
data: [...uint8Array] // не отправляем в JSON, размер изображения увеличится
});
setLoading(false);
console.log(response);
} catch (e) {
console.error(e.message, 'function handleSubmit')
}
};
if(!fileRef.current) return void null;
const reader = new FileReader();
reader.onloadend = () => {
const uint8Array = new Uint8Array(reader.result);
setLoading(true);
fetchData(uint8Array);
};
// рекомендованный метод
reader.readAsArrayBuffer(fileRef.current[0]);
// метод reader.readAsBinaryString(fileRef.current[0])
// согласно MDN,
// уже был однажды удален из File API specification,
// но после его вернули
// в использование, но все же рекомендуют
// использовать readAsArrayBuffer
// https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsBinaryString
}, []);
const nodeDom = (
<form onSubmit={handleSubmit}>
<div>
<input
onChange={e => fileRef.current = e.target.files}
accept="image/*"
type="file"
id="button-file"
/>
</div>
<button type="submit">{loading ? 'Сохраняю...' : 'Сохранить'}</button>
</form>
);
return nodeDom
}
export default App;
const express = require("express");
const cors = require("cors");
const crypto = require('crypto');
const fs = require('fs');
const PORT = 8080;
const app = express();
app.use(express.static("public"));
app.use(express.json({ limit: "50mb" }));
app.use(cors());
app.post("/api/upload_avatar", (req, res) => {
console.log(req.body);
const randomString = crypto.randomBytes(5).toString('hex');
const stream = fs.createWriteStream(`./public/images/${randomString}.png`);
stream.on('finish', function () {
console.log('file has been written');
res.end('file has been written');
});
stream.write(Buffer.from(req.body), 'utf-8');
stream.end();
});
app.listen(PORT, () => console.log(`Server running at ${PORT}`));
Автор: Имран Гаджиев
Источник [14]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/348933
Ссылки в тексте:
[1] Двоичная система счисления: https://ru.wikipedia.org/wiki/%D0%94%D0%B2%D0%BE%D0%B8%D1%87%D0%BD%D0%B0%D1%8F_%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0_%D1%81%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F
[2] Кодовая страница: https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%B4%D0%BE%D0%B2%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0
[3] ASCII: https://ru.wikipedia.org/wiki/ASCII
[4] Unicode: https://ru.wikipedia.org/wiki/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4
[5] Бит: https://ru.wikipedia.org/wiki/%D0%91%D0%B8%D1%82
[6] байт: https://ru.wikipedia.org/wiki/%D0%91%D0%B0%D0%B9%D1%82
[7] Формат hex: https://ru.wikipedia.org/wiki/%D0%A8%D0%B5%D1%81%D1%82%D0%BD%D0%B0%D0%B4%D1%86%D0%B0%D1%82%D0%B5%D1%80%D0%B8%D1%87%D0%BD%D0%B0%D1%8F_%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0_%D1%81%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F
[8] Двоичный файл: https://ru.wikipedia.org/wiki/%D0%94%D0%B2%D0%BE%D0%B8%D1%87%D0%BD%D1%8B%D0%B9_%D1%84%D0%B0%D0%B9%D0%BB
[9] Буффер и потоки nodejs: https://habr.com/ru/company/ruvds/blog/348970/
[10] ArrayBuffer и Uint8Array: https://learn.javascript.ru/arraybuffer-binary-arrays
[11] FileReader: https://developer.mozilla.org/en-US/docs/Web/API/FileReader/FileReader
[12] hex-agent-smith: https://hexed.it#base64:agent_smith_matrix_revolution.jpg;/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAIBAQEBAQIBAQECAgICAgQDAgICAgUEBAMEBgUGBgYFBgYGBwkIBgcJBwYGCAsICQoKCgoKBggLDAsKDAkKCgr/2wBDAQICAgICAgUDAwUKBwYHCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgr/wgARCAHgAoADASIAAhEBAxEB/8QAHQAAAgMBAQEBAQAAAAAAAAAABQYDBAcIAgEACf/EABoBAAIDAQEAAAAAAAAAAAAAAAECAAMEBQb/2gAMAwEAAhADEAAAAeYjJ0hh5vkW7DXVVX9DGyLMDjESPJTFCiR6OVCQMxCJ2oj74liel9+otUp8vhVYqGNo9ehaFGWfQ/zGbPNSGKX804ICLrnWkoIUt1ysBuOJjMZ+9TiYCYK+IJY4IxcBbwPpyfU30CfXNMtGKtDUSWWioSkAbDVCem5/onLK+odRerE5EtbNlvZxrVK3SuT8QpXyScEvhV+FBhYIOv2KUIFvSXwRcIh2cgeSjmrKe0Kp+wy3BxRAsTxXrCKuQT5GPDCFISCjfpE+69muxuWqhsIveJ/UIuner2WLda5S0k9dHkDVcvD5kWjcq3KbIactQn5PDcBuwevjLaqlxYn5rWTMBRBeUmsEzQZgeGVFnXVWEcaisPqsTqiA8mKrj7fPmSWX0iw6VWvtCiz1j0aCNdY0LYs26v4k9FBpKvRFifR8FlXCOfdP5J0c+QlzwTqYpvHusykK/wC8RWkJdrpFp2RW4gS4KTlJPTuw0FAOhDWg/iYMmIHI0Z4atiCbFCkX2ix+V7NEi7WljJlNr5gCjUnrFoIpInYBPWH6yXLCC8Sf5UtBfF+mWqcFWvUAfZwWUEj8+oWU8Js1FX2ZCXY5NSaFVQRZF1hIqQe/wX3NStk2s0J4udH2xYb22jjLDcpZFKEyyGuNZfVQEFyGt4tRvSkZrwx4JKpoG4dV78QzxX3Gp2U8OquiHOjixKvZrdjJerR/QCc/qERdck52KgmVUYhCUcVysIpENfue3JFfQBCQRpMDT/PeBrVMjVaV6F+kZajl8mRFRtxhDRtppdjhzq1bazDvlV0=
[13] прекрасный пример: https://gitlab.com/ImaGadzhiev/filereader.git
[14] Источник: https://habr.com/ru/post/491548/?utm_source=habrahabr&utm_medium=rss&utm_campaign=491548
Нажмите здесь для печати.