axios使用protobuf進行通信

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…

相關文章
相關標籤/搜索