TSRPC入门笔记

269 阅读6分钟

TSRPC 作为一个专门为 TypeScript 设计的 RPC (远程过程调用) 框架,通过它的介绍可以看出,它旨在解决前后端通信中的一系列常见问题,如沟通成本高、类型安全缺失、数据类型支持有限、安全性问题、技术框架不兼容、平台差异以及缺乏对 TypeScript 高级类型的支持等。通过提供一系列创新特性,TSRPC 旨在提升开发效率,确保类型安全,同时支持更多数据类型的传输,包括二进制数据,以及提供对 Serverless 架构的支持。

其实吧,看官网的入门比我这个文章强。至于当初为什么写,现在为什么要发出来?刚好最近又用到了,但是好多东西还要重新看文档再理解。

啊?这,不是现成的机会吗?[手动狗头]

官网传送门@TSRPC - 专为 TypeScript 设计的全栈 RPC 框架

关键特性

  • 类型安全:通过 TypeScript 的类型系统,实现编译时的类型校验,减少运行时错误。
  • 支持二进制传输:提高数据传输效率和安全性。
  • 跨平台兼容:支持浏览器、小程序、Node.js 等多个平台,方便构建全栈应用。
  • Serverless 支持:适配多种云平台的 Serverless 架构,简化部署和运维。
  • 一键生成接口文档:自动化文档生成,提高开发效率和接口透明度。
  • 多协议支持:同时支持 HTTP 和 WebSocket,满足不同场景的需求。

创建项目

首先,确保你有 NodeJS 12 或以上版本。你可以通过运行 node -v 来检查你的 NodeJS 版本。

写文章时候用的版本是18,小版本忘了

使用 create-tsrpc-app 脚手架工具来创建一个新的 TSRPC 项目。你可以选择使用 npxyarn 来执行这个命令:

npx create-tsrpc-app@latest
# 或者
yarn create tsrpc-app

这个命令会启动一个交互式的会话,让你选择一些基本的配置选项,比如项目名称和是否包含某些特性或依赖。

image-20240512184503657.png

前端yarn失败问题不大,进目录再看看,估计也没啥大问题

项目结构

创建完项目后,你会得到一个包含前后端的全栈项目结构,大致如下:

# 查看当面目录,指定10层深度 忽略了俩目录
/UserHub$ tree -l 10 --ignore node_modules --ignore .svcode 
▅ 
/project/blog/UserHub
├── backend
|  ├── Dockerfile
|  ├── README.md
|  ├── package.json
|  ├── src
|  |  ├── api
|  |  |  ├── ApiAddData.ts
|  |  |  └── ApiGetData.ts
|  |  ├── index.ts
|  |  └── shared
|  |     └── protocols
|  |        ├── PtlAddData.ts
|  |        ├── PtlGetData.ts
|  |        ├── base.ts
|  |        └── serviceProto.ts
|  ├── test
|  |  ├── api
|  |  |  └── data.test.ts
|  |  └── tsconfig.json
|  ├── tsconfig.json
|  ├── tsrpc.config.ts
|  └── yarn.lock
├── frontend
|  ├── README.md
|  ├── babel.config.js
|  ├── package.json
|  ├── public
|  |  ├── favicon.ico
|  |  └── index.html
|  ├── src
|  |  ├── App.less
|  |  ├── App.vue
|  |  ├── client.ts
|  |  ├── env.d.ts
|  |  ├── main.ts
|  ├── tsconfig.json
|  └── vue.config.js
└── vetur.config.js

directory: 494 file: 5356 symboliclink: 1

ignored: directory (17)

简单解释一下这些目录和文件

后端(backend

  • Dockerfile: 用于创建 Docker 容器的配置文件,可以让应用容易地在不同环境中部署和运行。

  • README.md: 通常包含项目的基本信息、安装指南、使用方法等。

  • package.json: 定义了项目的依赖库、脚本命令和其他配置信息。

  • src: 源代码目录。

  • api: 存放具体的 API 实现文件,例如 ApiAddData.tsApiGetData.ts,这些文件通常包含处理客户端请求的逻辑。

  • index.ts: 项目的入口文件,用于启动服务。

  • shared: 存放前后端共享的代码,如协议定义。

    • protocols: 包含 TSRPC 协议定义文件,如 PtlAddData.tsPtlGetData.ts,这些文件定义了 API 请求和响应的数据结构。
  • test: 包含测试代码,用于对 API 进行单元测试或集成测试。

  • tsconfig.json: TypeScript 的配置文件,定义了编译选项和项目设置。

  • tsrpc.config.ts: TSRPC 框架的配置文件,可以在这里配置 TSRPC 的行为,如设置协议路径、启用二进制传输等。

前端(frontend

  • README.md: 通常包含前端项目的基本信息、安装指南、使用方法等。

  • babel.config.js: Babel 的配置文件,用于将 ES6+ 代码转换为向后兼容的 JavaScript 代码。

  • package.json: 定义了前端项目的依赖库、脚本命令和其他配置信息。

  • public: 存放静态资源文件,如 favicon.icoindex.html

  • src: 前端项目的源代码目录。

    • App.less: 定义了 Vue 应用的样式。
    • App.vue: Vue 应用的根组件。
    • client.ts: TSRPC 客户端的初始化和配置,用于与后端进行通信。
    • env.d.ts: TypeScript 的环境声明文件,用于声明全局变量类型。
    • main.ts: 前端应用的入口文件,用于初始化 Vue 应用。
  • tsconfig.json: TypeScript 的配置文件,定义了编译选项和项目设置。

  • vue.config.js: Vue CLI 的配置文件,可以自定义 Vue 项目的构建和开发服务器等设置。

  • vetur.config.js: Vetur 插件的配置文件,用于在 Vue 项目中提供更好的开发体验,如语法高亮和代码自动完成。

刚刚自动安装依赖的时候不是报错了吗?我们再去前端项目中试一下

cd frontend
yarn
warning @vue/cli-service > @intervolga/optimize-cssnano-plugin > cssnano-preset-default > postcss-svgo > svgo > stable@0.1.8: Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility
[2/4] Fetching packages...
error @achrinza/node-ipc@9.2.2: The engine "node" is incompatible with this module. Expected version "8 || 10 || 12 || 14 || 16 || 17". Got "18.17.1"
error Found incompatible module.
info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.
plyue@/home/blog/UserHub/frontend$ npm ls @achrinza/node-ipc
UserHub-frontend@0.1.0 /media/plyue/662C8A672C8A31DB6/project/blog/UserHub/frontend
└── (empty)

本人没文化,这个包@achrinza/node-ipc不认识也不知道这个是用了做进程通信的。

这个错误大概的意思是,这个包和我本地的node18,作为一个没有安装过NVM的程序员我决定略过它

npm i
# balabala
added 1532 packages in 20s

146 packages are looking for funding
  run `npm fund` for details

对,世上无难事只要肯放弃嘛,解决问题😸

运行项目

要运行项目,你需要分别在前端和后端目录下启动开发服务器:

# 启动后端服务
cd backend
npm run dev

# 启动前端服务
cd frontend
npm run dev

这会启动本地开发服务器,并且当你修改代码并保存时,服务器会自动重启,让你能实时看到变化。

image-20240512191516328.png

访问 http://localhost:8080/

image-20240512191656081.png

构建项目

当你准备将你的应用部署到生产环境时,你需要构建你的项目。这可以通过在前端和后端项目下运行构建命令完成:

# 构建后端
cd backend
npm run build

# 构建前端
cd frontend
npm run build

构建完成后,输出的文件会放在各自项目的 dist 目录下,这些文件是准备好的生产环境代码,可以直接部署。

小贴士

  • 建议总是先启动后端服务,再启动前端服务,这样可以确保前端能正确地与后端通信。
  • 如果你遇到任何问题,可以查看 create-tsrpc-app 的帮助信息,或者访问 TSRPC 的官方文档和社区寻求帮助。

实现API接口

使用 TSRPC 开发 API 接口前,必须先了解几个重要的概念。

  • API 接口
    • API 接口就相当于一个实现在远端的异步函数
    • 这个函数的输入参数叫做 请求(Request),返回值叫做 响应(Response)
  • 协议(Protocol)
    • API 接口的类型定义,包括它的请求类型和响应类型
  • 实现函数(Implementation)
    • API 接口的功能实现,接收请求并返回响应
  • 服务端(Server)
    • API 接口的实现端,NodeJS 12 以上
  • 客户端(Client)
    • API 接口的调用端,支持多个平台,如浏览器、小程序前端,或是 NodeJS 后端微服务调用

实现一个 API 接口,只需要 3 个步骤: 定义协议 -> 服务端实现 -> 客户端调用

定义协议

1 个接口对应 1 个协议文件,TSRPC 按照命名来识别,规则如下:

  • 协议文件命名为 Ptl{接口名}.ts,统一放置在 backend/src/shared/protocols 下,允许子目录嵌套

  • 协议包含请求类型

    Req{接口名}及响应类型Res{接口名}

    • 通过 TypeScript 的 interfacetype 定义
  • API 接口的实际请求路径为{协议路径}/{接口名}

    • 协议路径:协议文件于协议目录的相对路径

定义协议是实现 API 接口的第一步,需要在 backend/src/shared/protocols 目录下创建对应的协议文件(例如 PtlLogin.ts)。这个文件中需要定义请求(ReqLogin)和响应(ResLogin)的类型。

backend/src/shared/protocols/user/PtlLogin.ts新建协议文件后tsrpc会自动在新文件内给出默认内容

image-20240512212633484.png

// backend/src/shared/protocols/user/PtlLogin.ts

// 请求
export interface ReqLogin {
    username: string;
    password: string;
}

// 响应
export interface ResLogin {
    user: {
        id: number;
        nickname: string;
    };
}

服务端实现

在服务端,每个 API 接口对应一个实现函数。这些函数通常位于 backend/src/api 目录下,并遵循一定的命名规则(例如 ApiLogin.ts)。

// backend/src/api/user/ApiLogin.ts
import { ApiCall } from "tsrpc";

export async function ApiLogin(call: ApiCall<ReqLogin, ResLogin>) {
    if (!(call.req.username === 'admin' && call.req.password === 'admin')) {
        call.error('用户名或密码错误');
        return;
    }

    call.succ({
        user: {
            id: 123,
            nickname: 'Test'
        }
    });
}

客户端调用

在客户端,使用 TSRPC 提供的客户端库(例如 tsrpc-browser)来调用远端 API,享受完整的代码提示和类型检查。

// 客户端示例代码
import { HttpClient } from 'tsrpc-browser';
import { serviceProto } from './shared/protocols/serviceProto';

const client = new HttpClient(serviceProto, {
    server: 'http://127.0.0.1:3000',
    json: true
});

async function login() {
    let ret = await client.callApi('user/Login', {
        username: 'admin',
        password: 'admin'
    });

    if (!ret.isSucc) {
        console.log('登录失败', ret.err.message);
        return;
    }

    console.log('登录成功', ret.res.user);
}

TSRPC 通过其类型安全的设计,让前后端开发者可以更加专注于业务逻辑的实现,而不是通信细节。它提供的客户端库和服务端框架简化了 API 的调用和实现过程,同时保持了高度的灵活性和扩展性。通过使用 TypeScript 的类型系统,TSRPC 还能确保接口的输入和输出在编译时就已经得到了校验,极大地提升了开发效率和代码质量。

说人话,就是我觉得最大的好处就是让全干工程师干起活儿来更嗨皮