avatar

mdo

Hello

  • 首页
  • 知识库
  • 归档
  • 标签
  • 关于
主页 通过网关代理类gateway动态分发客户端的调用
文章

通过网关代理类gateway动态分发客户端的调用

发表于 2026-06-10 更新于 2026-06- 14
作者 mdo
9~12 分钟 阅读

针对方案一(通过网关代理类动态分发),客户端如果同样是 TP 项目,由于服务端在 config/swoole.php 中只向官方扩展注册了一个固定的服务标识 gateway,客户端的调用方式也需要做出相应的配合。

以下是客户端对应的具体调用写法,分为快捷调用和优雅的代理类调用(推荐)两种:

写法 A:通过 RPC 门面直接快捷调用

这是最直接的写法,客户端直接连接服务端的 gateway 标识,并将实际的目标服务名和方法名作为参数打包传过去:

php

namespace app\controller;

use think\swoole\facade\RPC;

class OrderController
{
    public function index()
    {
        // 1. 连接服务端配置的 'gateway' 服务
        // 2. 调用服务端的 __call 魔术方法,依次传入:[目标服务标识, 目标方法名, 实际参数]
        $userInfo = RPC::user('gateway')->execute('user', 'getInfo', ['uid' => 99]);

        return json($userInfo);
    }
}

请谨慎使用此类代码。

注: 这里的 execute 是在服务端 RpcGateway 类中可以自由定义的方法名(如果服务端用的是 __call,客户端这里写任何方法名如 run()、do() 都可以,因为服务端都会通过魔术方法接收)。


写法 B:高级代理写法(完美复刻本地调用感,推荐)

写法 A 虽然能用,但代码看起来不够优雅,且失去了 IDE 的代码提示。在实际开发中,更推荐在客户端编写一个本地动态代理类,让调用端维持 UserService->getInfo() 这种完全面向对象的原生体验。

1. 客户端创建动态代理基类

在客户端创建一个公共的代理基类 app\rpc\client\BaseProxy.php,用来封装向服务端 gateway 发送请求的底层逻辑:

php

namespace app\rpc\client;

use think\swoole\facade\RPC;

abstract class BaseProxy
{
    // 子类需要定义自己对应服务端的哪个“动态服务标识”
    protected $serviceAlias = '';

    /**
     * 利用魔术方法,自动拦截客户端调用的所有方法
     */
    public function __call($methodName, $arguments)
    {
        // 自动打包:[ 动态服务标识, 调用的方法名, 传入的参数 ]
        return RPC::user('gateway')->execute(
            $this->serviceAlias, 
            $methodName, 
            $arguments
        );
    }
}

请谨慎使用此类代码。

2. 客户端为每个远程服务定义一个空类

有了基类后,客户端如果要调用服务端的 user 服务,只需要继承基类并指定标识即可。
创建 app\rpc\client\UserService.php:

php

namespace app\rpc\client;

/**
 * 用户远程服务代理
 * @method array getInfo(int $uid)  <-- 在这里写注解,IDE 就会有完美的代码提示!
 */
class UserService extends BaseProxy
{
    // 对应服务端动态映射表(如 Redis/数据库)里的键名
    protected $serviceAlias = 'user'; 
}

请谨慎使用此类代码。

3. 客户端控制器中的最终调用

通过上述代理封装后,你在控制器或者 Service 层调用时,完全感知不到“网关分发”的存在,代码极度干净:

php

namespace app\controller;

use app\rpc\client\UserService;

class Index
{
    protected $userService;

    // 通过 TP6 容器自动注入代理类
    public function __construct(UserService $userService)
    {
        $this->userService = $userService;
    }

    public function getUser()
    {
        // 像调用本地方法一样,IDE 还能正常提示方法和参数
        $result = $this->userService->getInfo(99);

        return json($result);
    }
}

请谨慎使用此类代码。


🛠️ 配合方案一的服务端微调提醒

为了配合客户端通过 execute 或者魔术方法调用,服务端 app\rpc\RpcGateway.php 的接收方法需要对应写成这样:

php

namespace app\rpc;

use think\Container;

class RpcGateway
{
    /**
     * 统一接收客户端的 execute 请求
     */
    public function execute(string $serviceAlias, string $methodName, array $realParams = [])
    {
        // 1. 从 Redis 或配置中动态获取类名
        $serviceClass = \think\facade\Cache::store('redis')->get("rpc:services:{$serviceAlias}");
        
        if (!$serviceClass || !class_exists($serviceClass)) {
            throw new \Exception("RPC服务 [{$serviceAlias}] 未注册");
        }

        // 2. 实例化并调用
        $serviceInstance = Container::getInstance()->make($serviceClass);
        
        return call_user_func_array([$serviceInstance, $methodName], $realParams);
    }
}

请谨慎使用此类代码。

这种设计下,如果未来你服务端新增了一个 goods 货品服务,你只需要在服务端的 Redis 里加一条映射,然后客户端直接新建一个继承 BaseProxy 的 GoodsService 类即可直接调用,两端都不需要重启 Swoole 进程。

技术
许可协议:  CC BY 4.0
分享

相关文章

7月 26, 2026

完美地解决 TP3 老系统数据的平滑读取

为了彻底、完美地解决 TP3 老系统数据的平滑读取,必须解决两个核心痛点: TP3 的盲猜反序列化机制(标量存原样,数组/对象存原生 serialize,同时兼容 json)。 TP3 与 TP6 的缓存前缀(Prefix)不一致。 以下是为你量身定制的终极落地解决方案,通

7月 26, 2026

thinkphp3 redis序列化和反序列化

在老系统重构迁移至 ThinkPHP 6 (TP6) 的过程中,ThinkPHP 3 (TP3) 的 Redis 序列化历史遗留问题是最核心的连环坑之一。 TP3 的 S('key', $value) 缓存方法和底层 Redis 驱动,在存储非字符串(如数组、对象)时,有一套独特的序列化行为。如果不

7月 24, 2026

Table 空间极易发生哈希冲突并溢出

既然你没有在业务中主动调用 Room,只使用了全局广播,那么这个问题就非常明确了:即使你不用房间功能,think-swoole 只要开启了 WebSocket,底层就会强行初始化并注入一个名为 Room 的驱动组件。 [1] 框架底层默认使用 table 类型来作为 Room 的存储介质。当进行全局

下一篇

轻量级开源全文搜索引擎:Manticore Search 入门介绍 - 实践

上一篇

原生的 fsockopen 或基于流的 socket 客户端

最近更新

  • 完美地解决 TP3 老系统数据的平滑读取
  • thinkphp3 redis序列化和反序列化
  • Table 空间极易发生哈希冲突并溢出
  • 将监控程序直接跑在云端
  • AI 驱动型 Facebook 群组关键词监控 Chrome 浏览器插件

热门标签

API CodeGeex Gitkraken Management Manticore Premiere Sublime Swoole ThinkPHP ThinkPHP5

目录

©2026 mdo. 保留部分权利。