中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

protobuf怎么在vue項目中使用

發布時間:2021-03-26 15:16:46 來源:億速云 閱讀:445 作者:Leah 欄目:web開發

protobuf怎么在vue項目中使用?針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

Protobuf簡單介紹

Google Protocol Buffer(簡稱 Protobuf)是一種輕便高效的結構化數據存儲格式,平臺無關、語言無關、可擴展,可用于通訊協議和數據存儲等領域。

有幾個優點:

1.平臺無關,語言無關,可擴展;
2.提供了友好的動態庫,使用簡單;
3.解析速度快,比對應的XML快約20-100倍;
4.序列化數據非常簡潔、緊湊,與XML相比,其序列化之后的數據量約為1/3到1/10。

個人感受: 前后端數據傳輸用json還是protobuf其實對開發來說沒啥區別,protobuf最后還是要解析成json才能用。個人覺得比較好的幾點是:

1.前后端都可以直接在項目中使用protobuf,不用再額外去定義model;
2.protobuf可以直接作為前后端數據和接口的文檔,大大減少了溝通成本;

沒有使用protobuf之前,后端語言定義的接口和字段,前端是不能直接使用的,前后端溝通往往需要維護一份接口文檔,如果后端字段有改動,需要去修改文檔并通知前端,有時候文檔更新不及時或容易遺漏,溝通成本比較大。 使用protobuf后,protobuf文件由后端統一定義, protobuf直接可以作為文檔 ,前端只需將protobuf文件拷貝進前端項目即可。如果后端字段有改動,只需通知前端更新protobuf文件即可,因為后端是直接使用了protobuf文件,因此protobuf文件一般是不會出現遺漏或錯誤的。長此以往,團隊合作效率提升是明顯的。

廢話了一大堆,下面進入正題。 我這里講的主要是在vue中的使用,是目前本人所在的公司項目實踐,大家可以當做參考。

思路

前端中需要使用 protobuf.js 這個庫來處理proto文件。

protobuf.js 提供了幾種方式來處理proto。

protobuf.load("awesome.proto", function(err, root) {...})
protobuf.load("awesome.json", function(err, root) {...})

眾所周知,vue項目build后生成的dist目錄中只有html,css,js,images等資源,并不會有 .proto 文件的存在,因此需要用 protobuf.js 這個庫將 *.proto 處理成 *.js 或 *.json ,然后再利用庫提供的方法來解析數據,最后得到數據對象。

PS: 實踐發現,轉化為js文件會更好用一些,轉化后的js文件直接在原型鏈上定義了一些方法,非常方便。因此后面將會是使用這種方法來解析proto。

預期目標

在項目中封裝一個 request.js 模塊,希望能像下面這樣使用,調用api時只需指定請求和響應的model,然后傳遞請求參數,不需關心底層是如何解析proto的,api返回一個Promise對象:

// /api/student.js 定義接口的文件
import request from '@/lib/request'

// params是object類型的請求參數
// school.PBStudentListReq 是定義好的請求體model
// school.PBStudentListRsp 是定義好的響應model
// getStudentList 是接口名稱
export function getStudentList (params) {
 const req = request.create('school.PBStudentListReq', params)
 return request('getStudentList', req, 'school.PBStudentListRsp')
}

// 在HelloWorld.vue中使用
import { getStudentList } from '@/api/student'
export default {
 name: 'HelloWorld',
 created () {

 },
 methods: {
 _getStudentList () {
  const req = {
  limit = 20,
  offset = 0
  }
  getStudentList(req).then((res) => {
  console.log(res)
  }).catch((res) => {
  console.error(res)
  })
 }
 }
}

準備工作

1.拿到一份定義好的proto文件。

雖然語法簡單,但其實前端不用怎么關心如何寫proto文件,一般都是由后端來定義和維護。在這里大家可以直接用一下我定義好的一份 demo 。

// User.proto
package framework;
syntax = "proto3";

message PBUser {
 uint64 user_id = 0;
 string name = 1;
 string mobile = 2;
}

// Class.proto
package school;
syntax = "proto3";

message PBClass {
 uint64 classId = 0;
 string name = 1;
}

// Student.proto
package school;
syntax = "proto3";

import "User.proto";
import "Class.proto";

message PBStudent {
 uint64 studentId = 0;
 PBUser user = 1;
 PBClass class = 2;
 PBStudentDegree degree = 3;
}

enum PBStudentDegree {
 PRIMARY = 0; // 小學生
 MIDDLE = 1; // 中學生
 SENIOR = 2; // 高中生
 COLLEGE = 3; // 大學生
}

message PBStudentListReq {
 uint32 offset = 1;
 uint32 limit = 2;
}

message PBStudentListRsp {
 repeated PBStudent list = 1;
}


// MessageType.proto
package framework;
syntax = "proto3";
// 公共請求體
message PBMessageRequest {
 uint32 type = 1;       // 消息類型
 bytes messageData = 2;      // 請求數據
 uint64 timestamp = 3;      // 客戶端時間戳
 string version = 4;       // api版本號

 string token = 14;       // 用戶登錄后服務器返回的 token,用于登錄校驗
}

// 消息響應包
message PBMessageResponse {
 uint32 type = 3;       // 消息類型
 bytes messageData = 4;      // 返回數據

 uint32 resultCode = 6;      // 返回的結果碼
 string resultInfo = 7;      // 返回的結果消息提示文本(用于錯誤提示)
}
// 所有的接口
enum PBMessageType {
 // 學生相關
 getStudentList = 0;       // 獲取所有學生的列表, PBStudentListReq => PBStudentListRsp
}

其實不用去學習proto的語法都能一目了然。這里有兩種命名空間 framework 和 school , PBStudent 引用了 PBUser ,可以認為 PBStudent 繼承了 PBUser 。

一般來說,前后端需要統一約束一個請求model和響應model,比如請求中哪些字段是必須的,返回體中又有哪些字段,這里用 MessageType.proto 的 PBMessageRequest 來定義請求體所需字段, PBMessageResponse 定義為返回體的字段。

PBMessageType 是接口的枚舉,后端所有的接口都寫在這里,用注釋表示具體請求參數和返回參數類型。比如這里只定義了一個接口 getStudentList 。

拿到后端提供的這份 *.proto 文件后,是不是已經可以基本了解到:有一個 getStudentList 的接口,請求參數是 PBStudentListReq ,返回的參數是 PBStudentListRsp 。

所以說proto文件可以直接作為前后端溝通的文檔。

步驟

1.新建一個vue項目

同時添加安裝 axios 和 protobufjs 。

# vue create vue-protobuf
# npm install axios protobufjs --save-dev

2.在 src 目錄下新建一個 proto 目錄,用來存放 *.proto 文件,并將寫好的proto文件拷貝進去。

此時的項目目錄和 package.json :

protobuf怎么在vue項目中使用

3.將 *.proto 文件生成 src/proto/proto.js (重點)

protobufjs 提供了一個叫 pbjs 的工具,這是一個神器,根據參數不同可以打包成xx.json或xx.js文件。比如我們想打包成json文件,在根目錄運行:

npx pbjs -t json src/proto/*.proto > src/proto/proto.json

可以在 src/proto 目錄下生成一個proto.json文件,查看請點擊這里。 之前說了:實踐證明打包成js模塊才是最好用的。我這里直接給出最終的命令

npx pbjs -t json-module -w commonjs -o src/proto/proto.js src/proto/*.proto

-w 參數可以指定打包js的包裝器,這里用的是commonjs,詳情請各位自己去看文檔。運行命令后在src/proto目錄下生成的 proto.js 。在chrome中 console.log(proto.js) 一下:

protobuf怎么在vue項目中使用

可以發現,這個模塊在原型鏈上定義了 load , lookup
等非常有用的api,這正是后面我們將會用到的。 為以后方便使用,我們將命令添加到package.json的script中:

"scripts": {
 "serve": "vue-cli-service serve",
 "build": "vue-cli-service build",
 "lint": "vue-cli-service lint",
 "proto": "pbjs -t json-module -w commonjs -o src/proto/proto.js src/proto/*.proto"
 },

以后更新proto文件后,只需要 npm run proto 即可重新生成最新的proto.js。

4. 封裝request.js

在前面生成了proto.js文件后,就可以開始封裝與后端交互的基礎模塊了。首先要知道,我們這里是用axios來發起http請求的。

整個流程:開始調用接口 -> request.js將數據變成二進制 -> 前端真正發起請求 -> 后端返回二進制的數據 -> request.js處理二進制數據 -> 獲得數據對象。

可以說request.js相當于一個加密解密的中轉站。在 src/lib 目錄下添加一個 request.js 文件,開始開發:

既然我們的接口都是二進制的數據,所以需要設置axios的請求頭,使用arraybuffer,如下:

import axios from 'axios'
const httpService = axios.create({
 timeout: 45000,
 method: 'post',
 headers: {
 'X-Requested-With': 'XMLHttpRequest',
 'Content-Type': 'application/octet-stream'
 },
 responseType: 'arraybuffer'
})

MessageType.proto 里面定義了與后端約定的接口枚舉、請求體、響應體。發起請求前需要將所有的請求轉換為二進制,下面是request.js的主函數

import protoRoot from '@/proto/proto'
import protobuf from 'protobufjs'
// 請求體message
const PBMessageRequest = protoRoot.lookup('framework.PBMessageRequest')
// 響應體的message
const PBMessageResponse = protoRoot.lookup('framework.PBMessageResponse')
const apiVersion = '1.0.0'
const token = 'my_token'
function getMessageTypeValue(msgType) {
 const PBMessageType = protoRoot.lookup('framework.PBMessageType')
 const ret = PBMessageType.values[msgType]
 return ret
}
/**
 * 
 * @param {*} msgType 接口名稱
 * @param {*} requestBody 請求體參數
 * @param {*} responseType 返回值
 */
function request(msgType, requestBody, responseType) { 
 // 得到api的枚舉值
 const _msgType = getMessageTypeValue(msgType)
 // 請求需要的數據
 const reqData = {
 timeStamp: new Date().getTime(),
 type: _msgType,
 version: apiVersion,
 messageData: requestBody,
 token: token
 }
}
 // 將對象序列化成請求體實例
 const req = PBMessageRequest.create(reqData)
 // 調用axios發起請求
 // 這里用到axios的配置項:transformRequest和transformResponse
 // transformRequest 發起請求時,調用transformRequest方法,目的是將req轉換成二進制
 // transformResponse 對返回的數據進行處理,目的是將二進制轉換成真正的json數據
 return httpService.post('/api', req, {
 transformRequest,
 transformResponse: transformResponseFactory(responseType)
 }).then(({data, status}) => {
 // 對請求做處理
 if (status !== 200) {
  const err = new Error('服務器異常')
  throw err
 }
 console.log(data)
 },(err) => {
 throw err
 })
}
// 將請求數據encode成二進制,encode是proto.js提供的方法
function transformRequest(data) {
 return PBMessageRequest.encode(data).finish()
}
function isArrayBuffer (obj) {
 return Object.prototype.toString.call(obj) === '[object ArrayBuffer]'
}
function transformResponseFactory(responseType) {
 return function transformResponse(rawResponse) {
 // 判斷response是否是arrayBuffer
 if (rawResponse == null || !isArrayBuffer(rawResponse)) {
  return rawResponse
 }
 try {
  const buf = protobuf.util.newBuffer(rawResponse)
  // decode響應體
  const decodedResponse = PBMessageResponse.decode(buf)
  if (decodedResponse.messageData && responseType) {
  const model = protoRoot.lookup(responseType)
  decodedResponse.messageData = model.decode(decodedResponse.messageData)
  }
  return decodedResponse
 } catch (err) {
  return err
 }
 }
}
// 在request下添加一個方法,方便用于處理請求參數
request.create = function (protoName, obj) {
 const pbConstruct = protoRoot.lookup(protoName)
 return pbConstruct.encode(obj).finish()
}
// 將模塊暴露出去
export default request

最后寫好的具體代碼請看: request.js 。 其中用到了 lookup() , encode() , finish() , decode() 等幾個proto.js提供的方法。

5. 調用request.js

在.vue文件直接調用api前,我們一般不直接使用request.js來直接發起請求,而是將所有的接口再封裝一層,因為直接使用request.js時要指定請求體,響應體等固定的值,多次使用會造成代碼冗余。

我們習慣上在項目中將所有后端的接口放在 src/api 的目錄下,如針對student的接口就放在 src/api/student.js 文件中,方便管理。 將 getStudentList 的接口寫在 src/api/student.js 中

import request from '@/lib/request'
// params是object類型的請求參數
// school.PBStudentListReq 是定義好的請求體model
// school.PBStudentListRsp 是定義好的響應model
// getStudentList 是接口名稱
export function getStudentList (params) {
 const req = request.create('PBStudentListReq', params)
 return request('getStudentList', req, 'school.PBStudentListRsp')
}
// 后面如果再添加接口直接以此類推
export function getStudentById (id) {
 // const req = ...
 // return request(...)
}

6. 在.vue中使用接口

需要哪個接口,就import哪個接口,返回的是Promise對象,非常方便。

<template>
 <div class="hello">
 <button @click="_getStudentList">獲取學生列表</button>
 </div>
</template>
<script>
import { getStudentList } from '@/api/student'
export default {
 name: 'HelloWorld',
 methods: {
 _getStudentList () {
  const req = {
  limit: 20,
  offset: 0
  }
  getStudentList(req).then((res) => {
  console.log(res)
  }).catch((res) => {
  console.error(res)
  })
 }
 },
 created () {
 }
}
</script>
<style lang="scss">
</style>

關于protobuf怎么在vue項目中使用問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

青海省| 蒙城县| 商洛市| 昆山市| 临西县| 平泉县| 民乐县| 武平县| 涿州市| 西乡县| 咸丰县| 天镇县| 堆龙德庆县| 平湖市| 子长县| 吴江市| 色达县| 松江区| 尼玛县| 桐庐县| 建德市| 专栏| 平阳县| 彭泽县| 阿坝| 历史| 嘉黎县| 台中县| 双江| 屏东县| 兴和县| 栖霞市| 砀山县| 尚义县| 个旧市| 惠安县| 法库县| 嘉定区| 甘孜| 噶尔县| 绥棱县|