在express开发的前后端调用中,express作为服务端是不二之选,它有一些很好用的body解析器来解析传入数据;而作为请求发起方,axios是非常方便的,这是一个很好的选择,它可以传输多种类型的数据给接收方。
通常我们用urlencoded或json编码传一些数据量小的信息是蛮不错的,但是如果数据量大的话,或者感觉编码效率低的话,可以考虑用blob或者arraybuffer,当然如果某些属性就是blob或者arraybuffer,直接传就好了,但是如果类似一些较大的json对象数组,类似数据库宽表的一页或者几页信息,真是占空间,自己设计转码还挺麻烦,有没有什么好的办法呢?
这里要推荐一下protobuf,protobuf 就是Protocol Buffer,它是一种由 Google 开发的二进制序列化格式和相关的技术,它用于高效地序列化和反序列化结构化数据,大名鼎鼎的gRPC里用的就是这个。当然在本文里,我不是让你放弃express+axios,彻底转向gRPC的怀抱,而是利用protobuf来提高我们接口的传输效率。
首先,需要定义下接口数据格式,用proto定义比json更为精准,每条数据的各属性类型顺序,如果支持一个请求里传输多条数据,只需要来一个repeated定义即可。

//dgiij.proto
package dgiijpackage;
syntax = "proto3";

message welcomeMessage {
	string id = 1;
	int64 timecount = 2;
	string url = 3;
}

message msgs
{
    repeated welcomeMessage msg = 1;
}

在原接口请求方和服务方简单增加两句,用于在数据发送前和收到后,进行转码和解码即可
下面是node客户端代码

//sender.js
const axios = require('axios');
var protobuf = require("protobufjs");
const root=protobuf.loadSync("dgiij.proto");
const dgiijMessage = root.lookupType("dgiijpackage.msgs");

let dataset=[{ "id": "dgiij","timecount":202407271054,"url":"https://blog.csdn.net/dgiij" },{ "id": "dgiij1","timecount":202407271134,"url":"https://blog.csdn.net/dgiij1" }];

var messageout = dgiijMessage.create({"msg":dataset});
var buffer = dgiijMessage.encode(messageout).finish();
 
axios.post('http://localhost:3000/sendmsg',buffer,{ headers: {'Content-Type': 'application/octet-stream'}}).then(res=>console.log(res.data))

axios.get('http://localhost:3000/getmsg',{responseType:'arraybuffer'}).then(res=>{
	let messagein = dgiijMessage.decode(res.data);
	console.log("解码数据为:");
	console.log(messagein.msg)
	messagein.msg.forEach(item=>{item.pasrelong=item.timecount.toNumber()})
	console.log("long类型转数字后数据为:");
	console.log(messagein.msg)
	})


下面是node服务端代码

//receiver.js
const protobuf = require("protobufjs");
const root=protobuf.loadSync("dgiij.proto");
const dgiijMessage = root.lookupType("dgiijpackage.msgs");

const express = require('express');
const app = express();

app.use("/", express.static("./"));

app.post('/sendmsg',express.raw(), (req, res)=> {
	let message = dgiijMessage.decode(req.body);
	console.log("解码数据为:");
	console.log(message.msg)
	message.msg.forEach(item=>{item.pasrelong=item.timecount.toNumber()})
	console.log("long类型转数字后数据为:");
	console.log(message.msg)
	res.json({"msg":"got"});
})

app.get('/getmsg', (req, res)=> {

let dataset=[{ "id": "dgiij","timecount":202407271054,"url":"https://blog.csdn.net/dgiij" },{ "id": "dgiij1","timecount":202407271134,"url":"https://blog.csdn.net/dgiij1" }];

var message = dgiijMessage.create({"msg":dataset});
var buffer = dgiijMessage.encode(message).finish();

res.set('Content-Type', 'arrarybuffer');
res.write(buffer);
res.end();
})


app.listen(3000, ()=> {
	console.log("Server is listening");
});

运行结果如下

在这里插入图片描述
在这里插入图片描述
下面这个是浏览器端测试网页

<html>
<head>
<script src="axios.min.js"></script>
<script src="protobuf.js"></script>
</head>
<body>
<div>protobuf test</div>
<script>
protobuf.load("./dgiij.proto").then(root=>{

const dgiijMessage = root.lookupType("dgiijpackage.msgs");

let dataset=[{ "id": "dgiij","timecount":202407271054,"url":"https://blog.csdn.net/dgiij" },{ "id": "dgiij1","timecount":202407271134,"url":"https://blog.csdn.net/dgiij1" }];
let messageout = dgiijMessage.create({"msg":dataset});
let buffer = dgiijMessage.encode(messageout).finish();
 
axios.post('http://localhost:3000/sendmsg',buffer,{ headers: {'Content-Type': 'application/octet-stream'}}).then(res=>console.log(res.data));

axios.get('http://localhost:3000/getmsg',{responseType:'arraybuffer'}).then(res=>{
	let messagein = dgiijMessage.decode(new Uint8Array(res.data));
	console.log(messagein.msg)
	})
});
</script>
</body>
</html>

效果如下
在这里插入图片描述
提醒注意下:浏览器端调用发送数据跟后端没有区别,但是接收数据的话要将返回数据按Uint8Array来解码,否则会报错,另外解码后的long型数字也不用转换了。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐