
Apache Thrift Node.js 示例实战指南从 RPC 服务到浏览器与 HTTP 跨语言调用【免费下载链接】thriftApache Thrift项目地址: https://gitcode.com/GitHub_Trending/thr/thrift本篇技术指南以 lib/nodejs/examples/README.md 为主线系统讲解 Apache Thrift 在 Node.js 生态中的完整示例体系如何用 Thrift 编译器生成 Node.js 绑定代码、如何启动基于 TCP 的 RPC 服务端与客户端、如何通过createWebServer让浏览器页面直接发起 RPC以及如何借助 HTTP 传输实现 Node.js 与 Python 之间的跨语言调用。读完本文你将能够独立跑通 Thrift Node.js 的全部示例并理解每个示例背后的传输层Transport、协议层Protocol与服务端Server组织方式为在真实项目中落地 Thrift 打好基础。示例总览examples 目录里有什么Apache Thrift 的 Node.js 语言库位于 lib/nodejs其示例目录 lib/nodejs/examples 共包含十余个文件覆盖了从最基础的 TCP RPC 到浏览器端、再到 HTTP 跨语言的三种典型用法示例文件作用依赖的 IDLuser.thrift定义UserProfile结构与UserStorage服务自身server.js / client.js基于 TCP 套接字的 RPC 服务端与客户端user.thrifthello.thrift定义HelloSvc、TimesTwo两个浏览器示例服务自身hello.js / hello.html浏览器端 JavaScript 客户端与对应的 Node.js Web 服务端hello.thrifthttpServer.js / httpClient.jsHTTP 传输的 Node.js 服务端与客户端hello.thrifthttpServer.py与 Node.js HTTP 客户端互通的 Python 服务端hello.thriftserver_multitransport.js / client_multitransport.js同时监听多种传输类型的进阶示例user.thriftparse.js无网络调用的纯解析示例user.thriftMakefile封装编译与启动命令方便一键运行—准备工作编译 Thrift 编译器与安装 Node.js 库运行所有示例前需要两样东西Thrift 编译器用于把.thriftIDL 文件翻译成各语言代码和Node.js 的 Thrift 运行时库。编译器仓库中编译器源码位于 compiler/cpp按其构建说明编译后得到thrift可执行文件示例与 Makefile 中均假定编译器二进制位于仓库根下的compiler/cpp/thrift。Node.js 库示例通过NODE_PATH../lib:../lib/thrift指向 lib/nodejs/lib 目录该目录下的thrift/子目录即运行时库源码其中封装了全部传输、协议与服务端实现。也可以直接用npm install thrift安装发布版但仓库内示例默认使用本地源码路径便于直接调试。需要特别说明的是示例中所有命令的执行目录都是 lib/nodejs/examples 本身因此文中凡出现../lib、gen-nodejs等相对路径均以该目录为基准。生成绑定代码从 IDL 到 JavaScript理解 IDLuser.thriftuser.thrift 是一个非常典型的 Thrift IDL定义了两种语言共享的数据结构与服务契约struct UserProfile { 1: i32 uid, 2: string name, 3: string blurb } service UserStorage { void store(1: UserProfile user), UserProfile retrieve(1: i32 uid) }它包含两个核心要素struct UserProfile一个包含uid32 位整数、name与blurb字符串三个字段的数据结构。字段前的1:、2:、3:是字段编号用于线协议wire protocol中的字段标识是 Thrift 保证前后兼容的关键。service UserStorage一个包含store写入与retrieve按 uid 读取两个方法的服务接口。服务是客户端与服务端之间 RPC 调用的契约。编译命令README 给出的生成绑定命令如下在lib/nodejs/examples目录下执行../../../compiler/cpp/thrift --gen js:node user.thrift ../../../compiler/cpp/thrift --gen js:node --gen py hello.thrift第一行针对user.thrift只生成 Node.js 绑定第二行针对hello.thrift同时生成 Node.jsjs:node与 Pythonpy两套绑定——这正是后面 HTTP 跨语言示例的基础。执行后会在当前目录下产出两类文件gen-nodejs/Node.js 专用绑定例如UserStorage.js服务端处理器接口与客户端 stub、user_types.jsUserProfile等类型定义。gen-js/浏览器端 JavaScript 绑定用于 hello.html 中的script引用。gen-py/Python 绑定被 httpServer.py 通过sys.path.append(gen-py)导入。以 server.js 为例生成代码的典型引用方式如下var UserStorage require(./gen-nodejs/UserStorage.js), ttypes require(./gen-nodejs/user_types);其中UserStorage同时充当服务端createServer的处理器参数与客户端createClient的客户端类ttypes则提供new ttypes.UserProfile({...})这样的类型构造能力。仓库中的 Makefile 将编译步骤封装成了make目标运行make或make all即可等价完成第一步的绑定生成all: ../../../compiler/cpp/thrift --gen js:node user.thrift第一个 RPC 示例基于 TCP 的 server.js 与 client.js这是 README 中Running the user example一节的核心场景。服务端与客户端通过 TCP 套接字在 9090 端口通信。启动服务端在终端一执行NODE_PATH../lib:../lib/thrift node server.jsNODE_PATH的作用是让 Node.js 在node_modules之外也能解析require(thrift)——../lib指向 lib/nodejs/lib../lib/thrift指向其下的thrift子目录二者共同保证运行时库可被加载。server.js 的核心实现如下var thrift require(thrift); var UserStorage require(./gen-nodejs/UserStorage.js), ttypes require(./gen-nodejs/user_types); var users {}; var server thrift.createServer(UserStorage, { store: function (user, result) { console.log(server stored:, user.uid); users[user.uid] user; result(null); }, retrieve: function (uid, result) { console.log(server retrieved:, uid); result(null, users[uid]); }, }); server.listen(9090);这里体现了 Thrift Node.js 服务端的两个关键约定thrift.createServer(Processor, handler)第一个参数传入生成的UserStorage处理器类第二个参数是业务实现对象。实现对象的每个方法签名都遵循(参数..., result)形式其中result是回调函数成功时调用result(null, 返回值)出错时调用result(err)。示例中用内存对象users模拟存储store按uid保存retrieve按uid返回。server.listen(9090)createServer返回的对象带有listen方法默认监听 TCP 端口 9090。运行客户端在终端二执行NODE_PATH../lib:../lib/thrift node client.jsclient.js 展示了客户端的三步曲——创建连接、创建客户端、发起调用var connection thrift.createConnection(localhost, 9090), client thrift.createClient(UserStorage, connection); var user new ttypes.UserProfile({ uid: 1, name: Mark Slee, blurb: Ill find something to put here., }); connection.on(error, function (err) { console.error(err); }); client.store(user, function (err, response) { if (err) { console.error(err); } else { console.log(client stored:, user.uid); client.retrieve(user.uid, function (err, responseUser) { if (err) { console.error(err); } else { console.log(client retrieved:, responseUser.uid); connection.end(); } }); } });值得注意的细节thrift.createConnection(localhost, 9090)建立到服务端的 TCP 连接thrift.createClient(UserStorage, connection)基于连接生成类型安全的客户端代理。new ttypes.UserProfile({...})用对象字面量构造 IDL 结构体实例字段名与user.thrift一一对应。所有 RPC 方法均为异步回调风格client.store(user, callback)与client.retrieve(uid, callback)。嵌套回调演示了先存储、后读取的调用链最后通过connection.end()主动关闭连接。客户端通过connection.on(error, ...)注册错误监听避免连接异常时进程崩溃。整个存储-读取闭环在服务端终端会依次打印server stored: 1与server retrieved: 1客户端终端则打印client stored: 1与client retrieved: 1从而验证 RPC 双向链路通畅。浏览器端调用hello.html 与 hello.jsREADME 特别提到For an example using JavaScript in the browser to connect to a node.js server look at hello.html, hello.js and hello.thrift。这是 Thrift Node.js 最具特色的能力之一——浏览器无需任何插件直接通过 XHR 调用 Node.js 服务端暴露的 RPC 接口。服务定义与编译hello.thrift 定义了浏览器示例所需的两个服务service HelloSvc { string hello_func(), } service TimesTwo { i64 dbl(1: i64 val), }编译时需同时生成 Node.js 与浏览器两套绑定README 中的第二条命令对hello.thrift执行../../../compiler/cpp/thrift --gen js:node --gen py hello.thrift其中js浏览器端生成到gen-js/js:nodeNode.js 端生成到gen-nodejs/。此外浏览器页面还需要 Thrift 的浏览器运行时库thrift.js将其复制到hello.html所在目录即 examples 目录。Web 服务端hello.jshello.js 使用thrift.createWebServer同时挂载两个服务并托管静态文件var thrift require(thrift); var HelloSvc require(./gen-nodejs/HelloSvc.js); var TimesTwoSvc require(./gen-nodejs/TimesTwo.js); var helloHandler { hello_func: function (result) { this.call_counter this.call_counter || 0; console.log(Client call: this.call_counter); result(null, Hello Apache Thrift for JavaScript this.call_counter); }, }; var timesTwoHandler { dbl: function (val, result) { console.log(Client call: val); result(null, val * 2); }, }; var helloService { transport: thrift.TBufferedTransport, protocol: thrift.TJSONProtocol, processor: HelloSvc, handler: helloHandler, }; var dblService { transport: thrift.TBufferedTransport, protocol: thrift.TJSONProtocol, processor: TimesTwoSvc, handler: timesTwoHandler, }; var ServerOptions { files: ., services: { /hello: helloService, /dbl: dblService, }, }; var server thrift.createWebServer(ServerOptions); var port 8585; server.listen(port); console.log(Http/Thrift Server running on port: port);这段代码揭示了createWebServer的配置模型它是理解 Thrift Node.js 服务端抽象的极佳范例ServiceOptions每个服务一套 I/O 栈每个服务由四个字段描述——transport传输层此处为thrift.TBufferedTransport即缓冲式传输、protocol协议层此处为thrift.TJSONProtocol即 JSON 协议、processor生成的处理器类、handler业务实现对象。ServerOptions服务器级配置files: .指定静态文件根目录因此hello.html可以被直接访问services用 URL 路径到 ServiceOptions 的映射把每个 RPC 端点挂到 Web 服务器上如/hello、/dbl。服务端监听8585端口同时提供静态页面服务与 RPC 端点。浏览器客户端hello.htmlhello.html 首先通过script依次引入浏览器运行时库与生成的客户端绑定script srcthrift.js typetext/javascript/script script srcgen-js/HelloSvc.js typetext/javascript/script script srcgen-js/TimesTwo.js typetext/javascript/script页面内两个按钮分别触发对/hello与/dbl端点的 RPC 调用其 JavaScript 逻辑展示了浏览器端 Thrift 客户端的三层组装function getMessage() { var transport new Thrift.TXHRTransport(http://localhost:8585/hello); var protocol new Thrift.TJSONProtocol(transport); var client new HelloSvcClient(protocol); var msg client.hello_func(); document.getElementById(output).innerHTML msg; } function dblMessage() { var transport new Thrift.TXHRTransport(http://localhost:8585/dbl); var protocol new Thrift.TJSONProtocol(transport); var client new TimesTwoClient(protocol); var val client.dbl(25); document.getElementById(output2).innerHTML val; }Thrift.TXHRTransport基于 XMLHttpRequest 的传输层构造参数是服务端 RPC 端点 URL负责把请求以 HTTP 形式发出。Thrift.TJSONProtocol协议层将调用序列化为 JSON与服务端thrift.TJSONProtocol严格对应。生成的客户端类HelloSvcClient、TimesTwoClient由编译器从hello.thrift生成浏览器端调用client.hello_func()、client.dbl(25)即可同步拿到结果并写入页面 DOM。运行步骤安装 Node.js官方推荐从 nodejs.org 获取在hello.js所在目录安装 Thrift Node 库npm install thrift该示例要求 Apache Thrift 0.9.2 及以上用thrift -gen js -gen js:node hello.thrift生成浏览器端与 Node.js 端绑定执行node hello.js启动 Web 服务端将浏览器运行时库thrift.js复制到hello.html所在目录浏览器访问http://localhost:8585/hello.html点击页面按钮即可观察 RPC 调用结果服务端终端会同步打印每次调用计数。HTTP 传输示例httpServer.js 与 httpClient.jsREADME 指出HTTP examples are provided also: httpClient.js and httpServer.js并且强调可以通过httpServer.py做**跨平台跨语言**测试。这套示例与前文的 WebServer 示例不同它不托管静态页面而是纯粹的 HTTP RPC 端点客户端使用createHttpConnection/createHttpClient显式建立 HTTP 连接。服务端httpServer.jshttpServer.js 是上述createWebServer用法的精简版只挂载一个/hello端点var helloHandler { hello_func: function (result) { console.log(Received Hello call); result(null, Hello from Node.js); }, }; var helloSvcOpt { handler: helloHandler, processor: helloSvc, protocol: thrift.TJSONProtocol, transport: thrift.TBufferedTransport, }; var serverOpt { services: { /hello: helloSvcOpt, }, }; var port 9090; thrift.createWebServer(serverOpt).listen(port); console.log(Http/Thrift Server running on port: port);注意它复用了 hello.thrift 中定义的HelloSvc服务因此编译时同样需要--gen js:node hello.thrift并在 9090 端口提供POST /hello形式的 HTTP RPC 端点。客户端httpClient.jshttpClient.js 展示了 HTTP 客户端的连接选项var options { transport: thrift.TBufferedTransport, protocol: thrift.TJSONProtocol, path: /hello, headers: { Connection: close }, https: false, }; var connection thrift.createHttpConnection(localhost, 9090, options); var client thrift.createHttpClient(helloSvc, connection); connection.on(error, function (err) { console.log(Error: err); }); client.hello_func(function (error, result) { console.log(Msg from server: result); });createHttpConnection(host, port, options)的 options 中transport与protocol必须与服务端保持一致这里都是TBufferedTransportTJSONProtocolpath指定 RPC 端点路径与services中的键一致https控制是否启用 TLSheaders可附加自定义 HTTP 头。随后createHttpClient生成客户端代理client.hello_func(callback)完成一次 HTTP RPC 调用并打印服务端返回的Hello from Node.js。跨语言互通httpServer.py为了让读者验证 HTTP 传输的跨语言能力README 特意提供了 Python 版本的服务端 httpServer.py其与 Node.js 客户端的配合方式如下编译hello.thrift时加上--gen py得到gen-py/下的 Python 绑定启动 Python 服务端同样监听 9090 端口同样使用TJSONProtocolimport sys sys.path.append(gen-py) from hello import HelloSvc from thrift.protocol import TJSONProtocol from thrift.server import THttpServer class HelloSvcHandler: def hello_func(self): print(Hello Called) return hello from Python processor HelloSvc.Processor(HelloSvcHandler()) protoFactory TJSONProtocol.TJSONProtocolFactory() port 9090 server THttpServer.THttpServer(processor, (localhost, port), protoFactory) print(Python server running on port str(port)) server.serve()运行 Node.js 的 httpClient.js即可看到客户端收到来自 Python 服务端的hello from Python。这里的互通性来自两端 I/O 栈的严格一致传输层都是 HTTP Buffered协议层都是TJSONProtocolPython 侧为TJSONProtocol.TJSONProtocolFactory()。只要 IDLhello.thrift与协议栈对齐Node.js 客户端与 Python 服务端或反向就能无缝通信——这正是 Thrift 跨语言设计的核心价值。进阶示例多传输类型与纯解析除 README 明确讲述的三个场景外examples 目录还提供了两个值得一读的进阶示例可作为理解 Thrift Node.js 传输层Transport抽象的补充。server_multitransport.js一次挂载多种传输server_multitransport.js 在同一进程中创建两个服务端实例分别监听不同端口并使用不同传输层var thrift require(thrift), ttransport require(thrift/transport); var server_framed thrift.createServer(UserStorage, { store: store, retrieve: retrieve, }); server_framed.listen(9090); var server_buffered thrift.createServer( UserStorage, { store: store, retrieve: retrieve, }, { transport: ttransport.TBufferedTransport }, ); server_buffered.listen(9091);9090 端口使用createServer的默认传输从 Thrift 0.9.x 起 Node.js 默认采用 framed transport即以长度前缀分帧的传输方式便于配合非阻塞服务端。9091 端口通过第三个参数{ transport: ttransport.TBufferedTransport }显式指定缓冲式传输。对应的 client_multitransport.js 展示了客户端如何针对不同传输类型分别建立连接。这个示例提醒开发者传输层Transport与协议层Protocol是正交的维度在跨语言、跨端口对接时必须确保两端选用一致的组合。parse.js不走网络的纯解析parse.js 展示了不需要任何网络连接的用法——直接利用生成的类型与协议/传输组件完成对象的序列化与反序列化。这类内存中解析模式常用于调试、数据转换或离线处理场景。总结Apache Thrift Node.js 的示例体系清晰地勾勒出三条递进的主线TCP RPCserver.js / client.jscreateServercreateConnection/createClient一个端口、一套类型安全的异步回调 API是生产环境最常用的服务形态浏览器端 RPChello.js / hello.htmlcreateWebServer把 RPC 端点与静态文件服务合二为一浏览器通过TXHRTransportTJSONProtocol直接调用打通了 Web 前端与 Node.js 后端HTTP 跨语言 RPChttpServer.js / httpClient.js / httpServer.py以 HTTP 为载体、JSON 为协议Node.js 客户端可以直接调用 Python 服务端验证了 Thrift 作为跨语言 RPC 框架的核心承诺。贯穿始终的要点是 Thrift 的分层 I/O 栈思想——传输层TBufferedTransport、framed、协议层TJSONProtocol、TBinaryProtocol等与业务处理器相互独立、自由组合。理解了这个模型你就能像 examples 目录中的示例一样针对不同场景灵活搭建自己的 Thrift Node.js 服务。如需继续深入可进一步阅读 lib/nodejs/lib 下的运行时源码以及 lib/nodejs/README.md 中关于 Node.js 库整体设计、测试与构建的说明。【免费下载链接】thriftApache Thrift项目地址: https://gitcode.com/GitHub_Trending/thr/thrift创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考