Thrift作为服务间RPC通信的流行方案,其本身是一个类型定义语言(IDL),由于其语言无关性,即可以一次编写服务数据类型定义和方法接口文档,然后通过工具生成指定平台语言的可调用的RPC服务代码。
本工具将 Thrift (IDL) 文件解析并生成TypeScript文件,可以用作前端服务请求方法相关代码的类型文档,这样在编写调用RPC方法代码时可利用TypeScript强大的类型支持提高开发效率。
Thrift除了定义IDL,还有一套自己的数据传输方法和协议,以便在RPC客户端和服务端之间通信,因此本工具也添加了RPC服务客户端代码的生成支持,利用所有生成的代码文件,可以完成一整套的完全基于Thrift的RPC调用。
Thrift官方提供了JS的生成工具,那么本工具的存在主要是为了解决以下问题:
* 官方生成的JS文件,适用于浏览器端的使用了大量全局变量,没有模块导出,并不适合我们常规模块化开发时引入
* 官方生成的Node JS,适用于Node客户端,由于大量使用了浏览器端不支持的net/http/Buffer模块,无法直接在浏览器端使用
* 官方生成的JS文件,没有Call sequence支持,如果服务端响应时间不一,可能造成回调顺序错误,一个解决办法就是每次的RPC调用都重生成Service Client和Connection实例,但是我更希望特别是WebSocket的connection实例能够重用,即在一个WebSocket连接上发送多个RPC调用,避免频繁的TCP连接打开和关闭
* 官方生成的JS文件,因为没有类型支持,对开发时静态检查和提示不便,因此本工具全部生成TypeScript代码
npm
npm install thrift2ts -g
yarn
yarn global add thrift2ts
t2t -i [thrift文件路径] -o [typescript文件输出目录] -r [request方法导入路径] -c
sample
t2t -i ./common.thrift -o ./services -r ./request -c
var thrift2ts = require('thrift2ts').default;
var thriftCode = 'XXX';
var tsCode = thrift2ts(thriftCode, './request')
Thrift
namespace java com.company.javabusz
namespace go com.company.gobusz
include "./Common.thrift"
enum EmployeeType {
Junior = 0,
Senior = 1,
Manager,
Director = 0xa
}
struct Employee {
1:required string name;
2:optional i32 age;
3:required map<string, i32> tasks;
}
exception NetworkException {
1:required i32 code;
2:required string message;
3:optional string url;
}
const i32 year = 2017
const list<string> languages = ['Java', 'Go', 'JavaScript']
const map<string, i32> lanAges = {'Java': 20, 'Go': 8, 'JavaScript': 16}
const bool happy = true
// This is a map definition
typedef map<string, number> EmployeesCatlog // a tail comment
service EmployeeOperator {
list<Employee> QueryEmployee(1:i32 age)
}
service EmployeeSalaryOperator extends EmployeeOperator {
bool OperateEmployeeSalaryByType(1:EmployeeType type, 2:i64 amount, 2:string note);
}
Convert to TypeScript
/**
* Auto generated by Thrift2Ts.
*
* Mon Jun 19 2017 22:42:06 GMT+0800 (CST)
*/
import Request from "./request";
import * as Common from "./CommonService";
export const year: number = 2017;
export const languages: string[] = ["Java", "Go", "JavaScript"];
export const lanAges: {[key: string]: number} = {"Java": 20, "Go": 8, "JavaScript": 16};
export const happy: boolean = true;
export enum EmployeeType {
Junior = 0,
Senior = 1,
Manager = 2,
Director = 10
}
export interface NetworkException {
code: number;
message: string;
url?: string;
}
export interface Employee {
name: string;
age?: number;
tasks: {[key: string]: number};
}
export function QueryEmployee(age: number): Promise<Employee[]> {
return Request<Employee[]>("EmployeeOperator.QueryEmployee", { age })
}
export function OperateEmployeeSalaryByType(type: EmployeeType, amount: number, note: string): Promise<boolean> {
return Request<boolean>("EmployeeSalaryOperator.OperateEmployeeSalaryByType", { type, amount, note })
}
export default {
QueryEmployee,
OperateEmployeeSalaryByType
}
本工具生成的文件包括一份RPC服务以及相关参数类型定义文档,这里会将Thrift的service下的所有方法转化为返回值为Promise的可直接引用的远程请求方法。为了灵活起见,代码不会实现如何去请求一个远端服务器。不论你用AJAX, Fetch抑或WebSocket网络请求方式,也不论你是用axios或者jQuery等哪一种网络请求库,或者说直接用本工具生成的Thrift Service Client搭配Thrift的数据传输协议,你直接提供实现了这些内容的模块的导入路径即可。
本代码中也提供了一些Request实现的例子
当要连接Thrift RPC服务时你必须导入 Browser Thrift 包, 它定义了 Thrift 数据传输协议。
这个包里面也有一份完整的使用本工具生成代码,并与Thrift RPC服务端通信的完整演示。