摘要:坑點一不支持瀏覽器環境首先你應該了解,它的目標是將編譯文件所生成的文件夾包含和文件。坑點二所提供的方法只支持回調函數以上是官方給出的例子,發送一個標準請求。
坑點一:ts-protoc-gen 不支持瀏覽器環境
首先你應該了解 ts-protoc-gen,它的目標是將編譯 .proto 文件所生成的文件夾包含 .js 和 .d.ts 文件。
但是...
因為當我們直接使用如下代碼時:
import { MyMessage } from "../generated/users_pb"; const msg = new MyMessage(); msg.setName("John Doe");
報錯:
Uncaught ReferenceError: exports is not defined.
這個錯誤應該不陌生,exports 未定義,多見于瀏覽器環境直接使用 node 環境代碼,所以我翻看了一下 ts-protoc-gen 的源碼,直到發現了如下代碼:
printer.printLn(`exports.${service.name} = ${service.name};`);
這里的 exports 就已經說明一切了,這個庫生成的是運行在 node 環境的 CommonJS 規范代碼,而對于使用 Webpack4 的 vue project 項目,也并不支持混合使用模塊系統,所以目前我想到了個臨時解決方案:
// 編譯文件導出方法和類時強制使用 `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
這個方法可以暫時解決 Uncaught ReferenceError: exports is not defined. 的問題。
坑點二:grpc-web-client 所提供的方法只支持回調函數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()); } } });
以上是官方給出的例子,發送一個標準請求。看到 callback 和一堆引入的文件的時候,我瞬間整個人就不好了,遂開始琢磨如何二次封裝 gRPC 請求。
首先可以先從 callback 函數轉成 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;
我們還可以再各這個請求加上超時限制(折騰一下準沒錯):
// callbackToPromise.js return utils.fetchTimeout(promiseFunc, 2000).catch(err => { // 設置 2000 ms 超時 if (err.code === "TIMEOUT") { // 提示超時 } }); // utils.js /** * fetch 超時 helper * * @param {Function} fetchPromise fetch 方法 * @param {Number} timeout 超時時間 * @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 函數專成 Promise 就完成了。
其次我們需要將 grpc-web-client 目標文件引入和回調函數的封裝分割開來,這樣也有利于之后代碼的維護:
// user.js /** * 根據用戶 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 /** * 創建請求 * * @param {Object} service service function * @param {Object} config 配置項 * @param {Function} transformValue 響應數據體轉換 * @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()); // 在這里我們可以運行數據轉化函數 } 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); } }); }
代碼很簡單,經過以上兩步驟,我們就可以如下輕松加愉快的去請求數據了:
import { queryUserDetails } from "@/api/user"; queryUserDetails(publicId) .then(res => console.log(res)) .catch(res => console.log(res));
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/108675.html
摘要:為了解決這一系列問題,微博從年開發了語言的框架,并基于此完成了服務化改造。這些經歷之下微博也積累了一套服務治理型的服務化體系。的版,所要解決的是微博平臺內部服務之間的調用,因此協議時,其實并沒有考慮到跨語言的問題,用的是對比較友好的。 showImg(https://segmentfault.com/img/remote/1460000012601596?w=1080&h=606); ...
摘要:帶入讓你的服務同時提供接口原文地址帶入讓你的服務同時提供接口項目地址前言接口需要提供給其他業務組訪問,但是協議不同無法內調,對方問能否走接口,怎么辦微信公眾號小程序等第三方回調接口只支持接口,怎么辦我相信你在實際工作中都會遇到如上問題,在中 帶入gRPC:讓你的服務同時提供 HTTP 接口 原文地址:帶入gRPC:讓你的服務同時提供 HTTP 接口項目地址:https://github...
摘要:,托管于騰訊云容器平臺容器編排工具。適配我們目前的服務部署在騰訊云托管,節點使用核的網絡增強型機器,所有的后端服務都以部署,集群外部署高可用支持集群內服務發現,數據庫以為主,消息隊列采用。 距離2017年的見聞技術架構調整接近2年,隨著業務線的發展,見聞技術部的項目數量、項目架構類型、基礎設施規模、服務變更頻率都在不斷地增長,帶給SRE的挑戰是如何能更快地助力于開發人員更快更穩定地部署...
摘要:原文地址能不能不用證書過去為什么不行因為僅支持標識,而標識必須使用傳輸層安全性的協議,此標識符用于應用層協議協商字段以及識別。 如果你以前有涉獵過 gRPC+gRPC Gateway 這兩個組件,你肯定會遇到這個問題,就是 為什么非得開 TLS,才能夠實現同端口雙流量,能不能不開? 又或是 我不想用證書就實現這些功能,行不行?。我被無數的人問過無數次這些問題,也說服過很多人,但說服歸說...
閱讀 1422·2021-11-15 11:38
閱讀 3567·2021-11-09 09:47
閱讀 1969·2021-09-27 13:36
閱讀 3211·2021-09-22 15:17
閱讀 2547·2021-09-13 10:27
閱讀 2862·2019-08-30 15:44
閱讀 1158·2019-08-27 10:53
閱讀 2702·2019-08-26 14:00