美好的一天。我在Reactjs(客户端)和Nodejs(服务器端)上进行了汇报。最近,在我的一个小项目中,出现了一个问题,即如何容易和简单地交换客户端-服务器类型的图像。今天,我们将学习如何从客户端发送二进制数据(特别是图像)并在服务器上处理它们。欢迎来到猫。如果您的Web应用程序是社交网络,Messenger或类似的东西,那么您肯定必须使用二进制数据,在大多数情况下,它是图像处理。将对此进行讨论。为了有一个大致的想法,我将对其进行顺序解释。看一下以下内容
- 二进制数系统和十进制数系统
- 代码页:ASCII,Unicode
- 位和字节
- 十六进制格式
- 二进制文件
- 缓冲区和Node.js线程
- ArrayBuffer和Uint8Array
- 文件阅读器
二进制数字系统和十进制数字系统。
这是一个用两个字符写的数字:一和零。简而言之,它是n(位数)的幂的2(基),例如,数字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
问题出现了。数字很清楚,但是文字呢?机器将如何将文本转换为二进制?一切都很简单。为此,存在诸如ASCII或Unicode之类的编码。这是一个简单的表(代码页),其中有一个到我们字符编号的映射,例如,字符“ S”是根据ASCII表的数字53,则计算机将以二进制形式显示数字53-110101。对于Unicode,这是一个强大的标准,其中包括UTF-8编码,在Web空间和类Unix系统中需求量很大。操作原理是通用的。位和字节
位是计算机测量信息的单位。而且我们已经知道计算机如何表示信息。是! 你是对的。一个位是1或0。对于计算机,1或0就像晶体管一样,为true或false。现在完全不难理解什么是字节-它是8位,也称为八位字节(类型由8个字节组成)。十六进制格式
我们传递给“十六进制”格式。我们讨论了二进制数字系统,十进制系统,除其他外,还有一个十六进制数字系统,排字员会明白我的意思。这是一个使用16个字符(从0-9和af)写入的数字。问题出现了:“为什么这么复杂?”。由于存储单元是8位字节,因此将其值写入两个十六进制数会更方便。另外,在Unicode标准中,字符编号通常以十六进制形式使用至少4位数字书写。此格式的工作方式如下:对于8位字节,它将按性别划分8位,即10101011-1010 | 1011,相应地转换各个部分后。1010-a,1011-b;const num = 196;
const hexNum = num.toString(16);
const initNum = parseInt(hexNum, 16);
二进制文件
我们继续进行下一项,它也称为二进制文件-它是字节数组。为什么是二进制?字节由位(即二进制数字系统的字符)组成,因此名称为二进制。绝对所有文件都适合二进制文件的类别,即包含文本,图像的文件-所有这些都是二进制文件,因此是二进制数据,因此是二进制数据。通常,二进制数据通过ASCII码页面字符以及十六进制格式(特别是图像)输出。我举一个例子。我们有以下图像:其部分可视化表示为hex-agent-smith手表附件
ASCII, hex , .
ArrayBuffer和Uint8Array
ArrayBuffer-使用javascript中的二进制数据的对象。修复使用二进制文件的内存长度。例如:new ArrayBuffer(256) -创建一个类似数组的对象,大小为256字节,不多-不多。每个字节都有特定的信息。ArrayBuffer不是数组,并且数组方法不适用于它。您问一个问题,如何使用?Uint8Array对象以无符号的8位数字(即0到255)给出ArrayBuffer表示形式。文件阅读器
FileReader?这是用于创建以下内容的构造函数:<input type="file">
下一步是什么?
现在考虑一个演示图像处理的好例子:- ReactJS模块
import React, {useState, useRef, useCallback} from 'react';
import axios from 'axios';
export const UPLOAD_AVATAR = 'http://localhost:8080/api/upload_avatar';
function App() {
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]
});
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]);
}, []);
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;
- ExpressJS模块
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}`));
总:
- 为什么我们需要编码
- 二进制数据的一般视图
- 推荐的字节发送方式
- 缓冲对象
- FileReader对象
- 钩子上的简单实现