# rpc中间件

# 安装使用

rpc中间件为独立中间件,需要单独安装使用

npm i sener-rpc
import { RPC } from 'sener-rpc';
new RPC();

# 基础使用

rpc 中间件用于远程调用支持,内部兼容了服务端和客户端请求,同时支持服务端和客户端使用。

import { Sener, Router } from 'sener';
import { RPC } from 'sener-rpc';

const router = new Router({
    '/demo': async ({ col, rpc }) => {
        const data = await rpc.comment.postReturn('/add', {content: 'xxx'});
        return { data: {success: true} };
    },
});

new Sener({
  middlewares: [router, new RPC({
    comment: 'http://localhost:9001/comment', // 指定 comment 服务的地址
  })],
});

# Request对象

Request 对象是RPC中的一个重要概念,Request对象封装了一些用于发起http请求的方法,同时支持服务端和客户端。以下是Request对象的类声明:

interface IRequestConsOptions {
    base: string,
    headers?: IJson<string>;
    traceid?: string;
}
export class Request {
    base: string;
    headers: IJson<string> = {};
    traceid: string = '';
    tk = '';
    setToken (tk: string) { this.tk = tk; };

    static Interceptor: IRPCRequestInterceptor;
    static OnResponse: IRPCRequestOnResponse;

    constructor (options: IRequestConsOptions);

    get<T=any> (url: string, query: IJson = {}): IRequestReturn<T>;
    post<T=any> (url: string, body: IJson = {}, form = false): IRequestReturn<T>;
    postForm<T=any> (url: string, body: IJson = {}): IRequestReturn<T>;
    async request<T> (options: IRequestOptions): IRequestReturn<T>;

    async postReturn<T=any> (url: string, body: IJson = {}): IParsedData;
    async getReturn<T=any> (url: string, query: IJson = {}): IParsedData;
    async requestReturn<T=any> (url: string, data: IJson = {}): IParsedData;

    parseResult<T = any> (result: IRouterReturn<T>): IParsedData;
}

# request方法

request 方法是发起http请求的基础方法

参数与返回值如下

interface ICommonRequestOptions {
    headers?: IJson<string>;
    traceid?: string;
}

interface IRequestOptions extends ICommonRequestOptions {
    body?: IJson,
    query?: IJson,
    url: string,
    method?: IMethod,
    data?: IJson,
    form?: boolean,
    traceid?: string,
    base?: string,
}
type IRequestReturn<T=any> = Promise<IRouterReturn>;
type IRouterReturn<T=any> = ISenerResponse<IRouterData<T>>;
interface ISenerResponse<T = any> {
  data: T,
  statusCode?: number,
  headers?: IJson<string>;
  success?: boolean;
}
interface IRouterData<T=any> {
    code: number;
    data: T;
    extra?: any;
    msg?: string;
    success?: boolean;
}

post、get、postForm 方法皆是封装了request方法,其中postForm方法用于发送formdata数据

# parseResult方法

parseResult 方法用于解析 IRequestReturn 数据,将其转换为 IParsedData

interface IBoolResult {
  success: boolean;
  msg?: string;
}
type IParsedData = IBoolResult & IJson;

postReturn、getReturn、requestReturn 方法会先调用相应的 request方法,然后将返回值通过 parseResult 转换之后返回。

# 拦截器

Request 有两个静态的拦截器,Interceptor 和 OnResponse

Interceptor 拦截器用于在请求开始之前拦截请求,可以对请求参数进行修改然后继续请求

或者是直接返回一个响应,就不会再发起请求了

interface IRPCResponse {
    success: boolean,
    data?: any,
    code?: number,
    msg: string,
    err?: any,
    [prop: string]: any,
}
type IRPCRequestInterceptor = (data: IRequestOptions) => void|IRPCResponse;

OnResponse 拦截器用于在请求完成之后,可以对请求返回结果进行修改。或者是直接返回一个新的响应

type IRPCRequestOnResponse = (data: IRPCResponse) => void|IRPCResponse;

# 自定义Request对象

我们可以通过继承Request对象来封装自己的服务业务逻辑

import { Request } from 'sener-rpc';
interface IUser {
    name: string;
    age: number;
    pwd: string;
}
class UserRequest extends Request {
    await regist(data: IUser){
        // 如果是使用ts,可以使用泛型获得更好的类型支持
        const data = await this.postReturn<IUser>('/user/regist', data);
        // 可以做一些业务逻辑处理
        return data;
    }
}

# 构造参数

构造参数支持传入键值对或者一个返回值为IJson<Request|any>的函数, 声明如下:

type IOptions = IJson<string> | ((traceid:string) => IJson<Request|any>);

# 使用键值对作为参数

使用键值对表示声明一组远程服务的名称和服务地址,如下图所示

new RPC({
    comment: 'http://localhost:9001/comment', // 指定 comment 服务的地址
    goods: 'http://localhost:9002', // 指定 商品 服务的地址
    // ...
})

rpc 会通过键值对构造 Request 对象来进行便捷的远程调用,基础使用的示例中 rpc.comment 便是一个 Request 对象。

# 使用函数作为参数

使用函数作为参数时,用于传入自定义的 Request对象,函数接受一个traceid的参数,该参数作用是用在服务端远程调用时保证traceid一致,需要作为 Request的构造参数。traceid与log中间件配合使用可以很有效的定位问题

使用如下


function createServices (traceid) {
    return { 
        user: new UserRequest({
            base: 'http://localhost:9001/user',
            traceid,
        }),
        comment: new CommentRequest({
            base: 'http://localhost:9002/comment',
            traceid,
        })
    };
}
new RPC(createServices);

# web客户端使用

客户端使用时需要用到 WebRPC 对象

import {WebRPC} from 'sener-rpc/dist/web.umd';

// 1. 单个服务可以传入base地址
const comment = new WebRPC('http://localhost:3001');
await comment.get('/message', {page: 1});

// 2. 多个服务传入map
const rpc = new WebRPC({
    user: 'http://localhost:3000', // user 服务的访问base地址
    comment: 'http://localhost:3001', // comment 服务的访问base地址
});
await rpc.comment.get('/message', {page: 1});

// 3. 使用继承方式
class Comment extends WebRPC {
    getList ({ app = 'common', index = 1 }: {
        app?: string
        index?: number
    } = {}) {
        return this.get('/message', {
            app,
            index,
            size: 10,
        });
    }
}
await (new Comment()).getList();

cdn 使用

<script src='https://cdn.jsdelivr.net/npm/sener-rpc'></script>
<script>
  SenerRpc.WebRPC
</script>
文档更新时间: 5/25/2023, 9:31:58 AM