成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

總結(jié)前端走 gRPC 協(xié)議所遇到的坑

Eminjannn / 805人閱讀

摘要:坑點(diǎn)一不支持瀏覽器環(huán)境首先你應(yīng)該了解,它的目標(biāo)是將編譯文件所生成的文件夾包含和文件??狱c(diǎn)二所提供的方法只支持回調(diào)函數(shù)以上是官方給出的例子,發(fā)送一個(gè)標(biāo)準(zhǔn)請(qǐng)求。

坑點(diǎn)一:ts-protoc-gen 不支持瀏覽器環(huán)境

首先你應(yīng)該了解 ts-protoc-gen,它的目標(biāo)是將編譯 .proto 文件所生成的文件夾包含 .js.d.ts 文件。

但是...


請(qǐng)不要將 ts-protoc-gen 生成的代碼直接用在瀏覽器中

因?yàn)楫?dāng)我們直接使用如下代碼時(shí):

import { MyMessage } from "../generated/users_pb";

const msg = new MyMessage();
msg.setName("John Doe");

報(bào)錯(cuò):

Uncaught ReferenceError: exports is not defined.

這個(gè)錯(cuò)誤應(yīng)該不陌生,exports 未定義,多見于瀏覽器環(huán)境直接使用 node 環(huán)境代碼,所以我翻看了一下 ts-protoc-gen 的源碼,直到發(fā)現(xiàn)了如下代碼:

printer.printLn(`exports.${service.name} = ${service.name};`);

這里的 exports 就已經(jīng)說明一切了,這個(gè)庫生成的是運(yùn)行在 node 環(huán)境的 CommonJS 規(guī)范代碼,而對(duì)于使用 Webpack4vue project 項(xiàng)目,也并不支持混合使用模塊系統(tǒng),所以目前我想到了個(gè)臨時(shí)解決方案:

// 編譯文件導(dǎo)出方法和類時(shí)強(qiáng)制使用 `es module`
// src/service/grpcweb.ts
printer.printLn(`var ${service.name} = (function () {`); // line 251
//  ||
//  ||
//  /
printer.printLn(`export var ${service.name} = (function () {`);



printer.printLn(`exports.${service.name} = ${service.name};`); // line 270
//  ||
//  ||
//  /
// delete



.printLn(`function ${service.name}Client(serviceHost, options) {`) // line 286
//  ||
//  ||
//  /
.printLn(`export function ${service.name}Client(serviceHost, options) {`)



printer.printLn(`exports.${service.name}Client = ${service.name}Client;`); // line 304
//  ||
//  ||
//  /
// delete

這個(gè)方法可以暫時(shí)解決 Uncaught ReferenceError: exports is not defined. 的問題。

坑點(diǎn)二:grpc-web-client 所提供的方法只支持回調(diào)函數(shù)
import {grpc} from "grpc-web-client";

// Import code-generated data structures.
import {BookService} from "./generated/proto/examplecom/library/book_service_pb_service";
import {GetBookRequest} from "./generated/proto/examplecom/library/book_service_pb";

const getBookRequest = new GetBookRequest();
getBookRequest.setIsbn(60929871);
grpc.unary(BookService.GetBook, {
  request: getBookRequest,
  host: host,
  onEnd: res => {
    const { status, statusMessage, headers, message, trailers } = res;
    if (status === grpc.Code.OK && message) {
      console.log("all ok. got book: ", message.toObject());
    }
  }
});

以上是官方給出的例子,發(fā)送一個(gè)標(biāo)準(zhǔn)請(qǐng)求??吹?callback 和一堆引入的文件的時(shí)候,我瞬間整個(gè)人就不好了,遂開始琢磨如何二次封裝 gRPC 請(qǐng)求。

首先可以先從 callback 函數(shù)轉(zhuǎn)成 Promise 下手:

// callbackToPromise.js
const promiseFunc = new Promise((resolve, reject) => {
  grpc.unary(BookService.GetBook, {
    request: getBookRequest,
    host: host,
    onEnd: res => {
      const { status, statusMessage, message } = res;
      if (status === grpc.Code.OK && message) {
        resolve(res)
      } else {
        reject(res);
      }
    }
  });
});

return promiseFunc;

我們還可以再各這個(gè)請(qǐng)求加上超時(shí)限制(折騰一下準(zhǔn)沒錯(cuò)):

// callbackToPromise.js
return utils.fetchTimeout(promiseFunc, 2000).catch(err => { // 設(shè)置 2000 ms 超時(shí)
  if (err.code === "TIMEOUT") {
    // 提示超時(shí)
  }
});

// utils.js
/**
 * fetch 超時(shí) helper
 *
 * @param {Function} fetchPromise fetch 方法
 * @param {Number} timeout 超時(shí)時(shí)間
 * @returns Promise
 */
function fetchTimeout (fetchPromise, timeout) {
  let abortFunc = null;
  const abortPromise = new Promise((resolve, reject) => {
    abortFunc = () => {
      reject({ code: "TIMEOUT", msg: "TIMEOUT" });
    };
  });

  const abortablePromise = Promise.race([
    fetchPromise,
    abortPromise
  ]);

  setTimeout(() => {
    abortFunc(path);
  }, timeout);

  return abortablePromise;
}

這樣 callback 函數(shù)專成 Promise 就完成了。

其次我們需要將 grpc-web-client 目標(biāo)文件引入和回調(diào)函數(shù)的封裝分割開來,這樣也有利于之后代碼的維護(hù):

// user.js

/**
 * 根據(jù)用戶 ID 查詢用戶信息
 *
 * @param {String} publicId 用戶 ID
 */
export function queryUserDetails (publicId) {
  const queryUserDetailsRequest = new QueryUserDetailsRequest();
  queryUserDetailsRequest.setUserPublicId(publicId);

  const config = {
    request: queryUserDetailsRequest,
    headers: {
      ...headers,
      ...makeAuthorizationHeader(utils.getToken())
    }
  };

  return createRequest(Dashboard.QueryUserDetails, config, transformQueryUserDetailsValue);
}
// api.config.js
/**
 * 創(chuàng)建請(qǐng)求
 *
 * @param {Object} service service function
 * @param {Object} config 配置項(xiàng)
 * @param {Function} transformValue 響應(yīng)數(shù)據(jù)體轉(zhuǎn)換
 * @returns Promise
 */
export function createRequest (service, config, transformValue) {
  const promiseFunc = new Promise((resolve, reject) => {
    ProgressBar.start();
    grpc.unary(service, {
      request: config.request,
      host: DASHBOARD_API,
      metadata: new grpc.Metadata(config.headers),
      onEnd: (res) => {
        const { status, statusMessage, message } = res;
        if (status === grpc.Code.OK && message) {
          ProgressBar.finish();
          resolve((transformValue && transformValue(message.toObject())) || message.toObject()); // 在這里我們可以運(yùn)行數(shù)據(jù)轉(zhuǎn)化函數(shù)
        } else if (status === grpc.Code.Unauthenticated) {
          ProgressBar.fatal();
          errorHandler.showNotice(grpc.Code[status], statusMessage);
          router.push({
            name: "unauthenticated",
            path: "/403"
          });
          reject(res);
        } else {
          ProgressBar.fatal();
          errorHandler.showNotice(grpc.Code[status], statusMessage);
          reject(res);
        }
      }
    });
  });

  return utils.fetchTimeout(promiseFunc, `${service.service.serviceName}.${service.methodName}`, TIMEOUT).catch(err => {
    if (err.code === "TIMEOUT") {
      const { code, msg } = err;
      ProgressBar.fatal();
      errorHandler.showNotice(code, msg);
    }
  });
}

代碼很簡單,經(jīng)過以上兩步驟,我們就可以如下輕松加愉快的去請(qǐng)求數(shù)據(jù)了:

import { queryUserDetails } from "@/api/user";

queryUserDetails(publicId)
  .then(res => console.log(res))
  .catch(res => console.log(res));

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/108675.html

相關(guān)文章

  • 明星分分合合的洪荒點(diǎn)擊量,微博Mesh服務(wù)化改造如何支撐?(附PPT下載)

    摘要:為了解決這一系列問題,微博從年開發(fā)了語言的框架,并基于此完成了服務(wù)化改造。這些經(jīng)歷之下微博也積累了一套服務(wù)治理型的服務(wù)化體系。的版,所要解決的是微博平臺(tái)內(nèi)部服務(wù)之間的調(diào)用,因此協(xié)議時(shí),其實(shí)并沒有考慮到跨語言的問題,用的是對(duì)比較友好的。 showImg(https://segmentfault.com/img/remote/1460000012601596?w=1080&h=606); ...

    ShowerSun 評(píng)論0 收藏0
  • 帶入gRPC:讓你的服務(wù)同時(shí)提供 HTTP 接口

    摘要:帶入讓你的服務(wù)同時(shí)提供接口原文地址帶入讓你的服務(wù)同時(shí)提供接口項(xiàng)目地址前言接口需要提供給其他業(yè)務(wù)組訪問,但是協(xié)議不同無法內(nèi)調(diào),對(duì)方問能否走接口,怎么辦微信公眾號(hào)小程序等第三方回調(diào)接口只支持接口,怎么辦我相信你在實(shí)際工作中都會(huì)遇到如上問題,在中 帶入gRPC:讓你的服務(wù)同時(shí)提供 HTTP 接口 原文地址:帶入gRPC:讓你的服務(wù)同時(shí)提供 HTTP 接口項(xiàng)目地址:https://github...

    LiangJ 評(píng)論0 收藏0
  • 華爾街見聞基于istio的服務(wù)網(wǎng)格實(shí)踐

    摘要:,托管于騰訊云容器平臺(tái)容器編排工具。適配我們目前的服務(wù)部署在騰訊云托管,節(jié)點(diǎn)使用核的網(wǎng)絡(luò)增強(qiáng)型機(jī)器,所有的后端服務(wù)都以部署,集群外部署高可用支持集群內(nèi)服務(wù)發(fā)現(xiàn),數(shù)據(jù)庫以為主,消息隊(duì)列采用。 距離2017年的見聞技術(shù)架構(gòu)調(diào)整接近2年,隨著業(yè)務(wù)線的發(fā)展,見聞技術(shù)部的項(xiàng)目數(shù)量、項(xiàng)目架構(gòu)類型、基礎(chǔ)設(shè)施規(guī)模、服務(wù)變更頻率都在不斷地增長,帶給SRE的挑戰(zhàn)是如何能更快地助力于開發(fā)人員更快更穩(wěn)定地部署...

    stonezhu 評(píng)論0 收藏0
  • gRPC+gRPC Gateway 能不能不用證書?

    摘要:原文地址能不能不用證書過去為什么不行因?yàn)閮H支持標(biāo)識(shí),而標(biāo)識(shí)必須使用傳輸層安全性的協(xié)議,此標(biāo)識(shí)符用于應(yīng)用層協(xié)議協(xié)商字段以及識(shí)別。 如果你以前有涉獵過 gRPC+gRPC Gateway 這兩個(gè)組件,你肯定會(huì)遇到這個(gè)問題,就是 為什么非得開 TLS,才能夠?qū)崿F(xiàn)同端口雙流量,能不能不開? 又或是 我不想用證書就實(shí)現(xiàn)這些功能,行不行?。我被無數(shù)的人問過無數(shù)次這些問題,也說服過很多人,但說服歸說...

    yanest 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<