proto通信資料 github.com/protocolbuf… github.com/dcodeIO/pro…前端
或者你能夠直接使用做者封裝好proto通信的開發腳手架 地址github.com/oujin-nb/vu…vue
Protocol Buffers 是一種輕便高效的結構化數據存儲格式,能夠用於結構化數據串行化,或者說序列化。它很適合作數據存儲或 RPC 數據交換格式。可用於通信協議、數據存儲等領域的語言無關、平臺無關、可擴展的序列化結構數據格式node
首先咱們以前使用Json進行通信是使用文本進行通信,而protobuf是使用二進制通信,通信效率能夠見下圖 webpack
這裏是介紹在es6前端模塊化項目中如何簡單高效的使用protobuf進行通信ios
首先理清思路:1 將通用的.proto文件解析生成前端可以使用的js文件 2將普通的js對象引用protobuf提供的方法序列化成指定的二進制數據 3 將後端傳來的數據解析成js對象git
步驟es6
1 解析.proto文件 準備一個文件夾專門來放.proto文件 github
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"start": "npm run dev",
"build": "node build/build.js",
"proto": "pbjs -t json-module -w commonjs -o src/configFile/proto/proto.js src/configFile/proto/*.proto"
},
複製代碼
直接執行 npm run proto
便會生成proto.js文件web
2 封裝proto請求typescript
一個完整的請求以下 首先看後臺給咱們的proto文件 BaseResponse
syntax = "proto3";
option csharp_namespace = "probofu.Controllers";
import "google/protobuf/any.proto";
message BaseResponse {
bool IsSuccess = 1;
string Message = 2;
string Token = 3;
google.protobuf.Any data = 4;
}
複製代碼
Person
syntax = "proto3";
option csharp_namespace = "probofu.Controllers";
message Person {
int32 Id = 1;
string Name = 2;
Address Address=3;
}
message Address {
string Line1 = 1;
string Line2 = 2;
}
複製代碼
引用生成的js文件發送請求以下
requestTest1() {
let person = require("@/configFile/proto/proto");
let protobufRoot = require("protobufjs").Root;
let root = protobufRoot.fromJSON(person);
let userInfo = root.lookupType("Person");
let BaseResponse = root.lookupType("BaseResponse");
let infoData = {Name:'xiaoming',Id:24};
// 將js對象序列化成二進制
let infoEncodeMessage = userInfo
.encode(userInfo.create(infoData))
.finish();
let blob = new Blob([infoEncodeMessage], {type: 'buffer'});
// 新建一個axios對象
const httpService = axios.create({
timeout: 45000,
method: "post",
headers: {
"X-Requested-With": "XMLHttpRequest",
"Content-Type": "application/octet-stream"
},
responseType: "arraybuffer"
});
httpService
.post(
"http://192.168.1.31:5000/api/system/getsth",
blob
)
.then(e => {
// 將二進制數據生成js對象
const buf = protobuf.util.newBuffer(e.data);
let res = BaseResponse.decode(buf);
let person = userInfo.decode(res.data.value);
});
},
複製代碼
可是在實際開發中咱們不能每次都這樣發送請求應該封裝一層,經過直接傳入請求參數模板和返參解析模板,作到傳入js對象請求完成後返回js對象,而通信的時候用protobuf進行通信
先準備一份配置文件
export default [
{ test:{url:'system/getsth',requestTmp:'Person',responseTmp:'Person'}},
]
複製代碼
補充配置文件通常是按照接口文檔往裏面寫,可是實際開發中每每有幾百個接口,寫起來來繁瑣並且容易出錯,我這邊的處理建議是讓後臺將接口文檔寫成固定格式的excel而後咱們前端直接解析excel生成js配置對象,這樣既方便又能甩鍋
方法以下(注意異步處理):
import axios from 'axios'
import XLSX from 'xlsx'
async function getConfigList(){
let interfaceList = []
// 讀取本地excel文件
let x = await axios({
url: "../../static/file/proto接口文檔.xlsx",
method: 'get',
responseType:'arraybuffer'
})
var data = new Uint8Array(x.data);
var arr = new Array();
for(var i = 0; i != data.length; ++i) arr[i] = String.fromCharCode(data[i]);
var bstr = arr.join("");
var workbook = XLSX.read(bstr, {type:"binary"});
workbook.SheetNames.forEach(y=>{
let jsonSheet = XLSX.utils.sheet_to_json(workbook.Sheets[y])
if(jsonSheet.length>0){
jsonSheet.forEach(z=>{
let interfaceObj={}
interfaceObj[z['路由']+z['方法名']]={
url:z['路由']+'/'+z['方法名'],
requestTmp:z['參數Proto文件'],
responseTmp:z['返回響應Proto']
}
interfaceList.push(interfaceObj)
})
}
})
return interfaceList
}
export default getConfigList
複製代碼
引入配置文件生成配置好可用做proto通信的axios對象並掛載在vue的原型上
import protoRoot from "@/configFile/proto/proto"
import protobuf from 'protobufjs'
import axios from 'axios'
import apiConfig from './protoApi/index'
// 基礎response模板
let BaseResponse = protoRoot.lookupType("BaseResponse");
const createRequest = (option) => {
return axios.create({
timeout: 10000,
method: "post",
headers: {
"X-Requested-With": "XMLHttpRequest",
"Content-Type": "application/octet-stream",
'token': localStorage.getItem("token")
},
baseURL: process.env.NODE_ENV == 'development' ? process.env.API_HOST : HOST,
responseType: "arraybuffer"
});
}
const getApiInstance = (option) => {
console.log(option)
// 根據參數配置請求模板和解析模板
let requetProto = protoRoot.lookupType(option.requestTmp);
let responseProto = protoRoot.lookupType(option.responseTmp);
let api = createRequest()
api.interceptors.request.use(
config => {
config.url = option.url;
let data = Object.assign({},config.data)
config.data = new Blob([requetProto.encode(requetProto.create(data)).finish()], { type: 'buffer' });
return config;
},
error => {
return Promise.reject(error);
}
);
api.interceptors.response.use(
response => {
const buf = protobuf.util.newBuffer(response.data);
let res = BaseResponse.decode(buf);
let resData = responseProto.decode(res.data.value);
return resData
},
error => {
}
);
return api
}
/*
若是採用excel生成js配置文件
*/
// const getApiMap = async () => {
// let apiList = {}
// let d = await apiConfig()
// d.forEach((s) => {
// let key = Object.keys(s)[0]
// let val = s[key]
// apiList[key] = getApiInstance(val)
// })
// return apiList
// }
/*
若是是手寫js配置文件
*/
const getApiMap = ()=>{
let apiList = {}
apiConfig.forEach((s)=>{
let key = Object.keys(s)[0]
let val = s[key]
apiList[key]= getApiInstance(val)
})
return apiList
}
getApiMap()
export default getApiMap()
複製代碼
掛載在vue的原型上
注意:若是你是採用讀取excel生成配置文件,那麼在main方法你將獲得一個promise對象(async方法返回一個primise對象)因此這裏咱們須要作同步處理
import api from '../src/config/protoReqConfig'
Vue.prototype.api = api
// excel文件生成配置文件
function creatVue(){
new Vue({
el: '#app',
router,
store,
components: {App},
template: '<App/>'
})
}
console.log(api)
api.then(x=>{
Vue.prototype.api = x // proto格式http請求
creatVue()
}).catch(x=>{
console.log('建立api對象失敗')
console.log(x)
creatVue()
})
複製代碼
3 實際應用 直接調用以前配置好的方法便可
this.api.test({data:{Name:'daming',Id:25}}).then((s)=>{
console.log(s)
})
複製代碼
github github.com/oujin-nb/vu…