xiaosongshu / nacos
A SDK for nacos service written in PHP. 简单的php版本nacos客户端
v1.1.0
2025-07-30 11:36 UTC
Requires
- php: >=7.1
- ext-curl: *
- ext-json: *
- ext-sockets: *
README
简单的php版本nacos客户端
安装
composer require xiaosongshu/nacos
项目地址
https://github.com/2723659854/nacos
客户端提供的方法
<?php require_once __DIR__.'/vendor/autoload.php'; $dataId = 'CalculatorService'; $group = 'api'; $serviceName = 'father'; $namespace = 'public'; $client = new \Xiaosongshu\Nacos\Client('http://127.0.0.1:8848','nacos','nacos'); var_dump("发布配置"); /** 发布配置 */ print_r($client->publishConfig($dataId, $group, json_encode(['name' => 'fool', 'bar' => 'ha']))); var_dump("获取配置需要稍等一秒左右,否则是404"); /** 获取配置 */ print_r($client->getConfig($dataId, $group,'public')); var_dump("监听配置是否发生了变化,有变化则有返回值,无变化则返回空,同时监听配置会阻塞几秒左右"); /** 监听配置 */ print_r($client->listenerConfig($dataId, $group, json_encode(['name' => 'fool', 'bar' => 'ha']))); var_dump("创建服务,一个服务可以有多个实例提供,一个实例只可以提供 一个服务,但是我这是服务于fpm所以可以一个实例节点可以提供多个服务"); /** 创建服务 */ print_r($client->createService($serviceName, $namespace, json_encode(['name' => 'tom', 'age' => 15]))); var_dump("给服务分配一个实例,否则服务是空的,相当于餐馆没有厨师提供服务,这里有一个坑,如果是创建临时实例,则不要创建服务,直接创建实例并指定为临时实例,否则会默认为永久实例而发生冲突"); /** 创建实例 */ print_r($client->createInstance($serviceName, "192.168.4.110", '9506', $namespace, ['name' => 'tom', 'age' => 15], 50, 1, true)); var_dump("获取服务列表,查看nacos上已注册了哪些服务"); /** 获取服务列表 */ print_r($client->getServiceList($namespace)); var_dump("查看这个服务的详细信息"); /** 服务详情 */ print_r($client->getServiceDetail($serviceName, $namespace)); var_dump("查看这个服务下有哪些实例可以提供这个服务,就是类似这个餐馆有哪些厨师可以提供炒菜服务"); /** 获取实例列表 */ print_r($client->getInstanceList($serviceName, $namespace)); var_dump("给临时实例发送一次心跳,发送心跳的参数必须和创建实例的参数一致才可以,否则实例不健康"); /** 发送心跳 */ sleep(1);print_r($client->sendBeat($serviceName, '192.168.4.110', '9506', $namespace,['name' => 'tom', 'age' => 15], true,50)); var_dump("发送心跳之后,再次获取实例列表,确认健康状态"); print_r($client->getInstanceList($serviceName, $namespace)); var_dump("获取实例的详情"); /** 获取实例详情 */ print_r($client->getInstanceDetail($serviceName, true, '192.168.4.110', '9506')); var_dump("移除某一个实例,要删除的实例必须和当初创建的实例的参数一致才可以删除"); /** 移除实例*/ print_r($client->removeInstance($serviceName, '192.168.4.110', 9505, $namespace, true));
应用举例
注册发布服务,监听配置
本项目提供已编写好的服务端Xiaosongshu\Nacos\Server
和客户端Xiaosongshu\Nacos\JsonRpcClient
。
你可以编写一个server.php文件,内容如下
<?php require_once __DIR__.'/vendor/autoload.php'; require_once __DIR__."/DemoService.php"; require_once __DIR__."/LoginService.php"; use Xiaosongshu\Nacos\Server; // 加载配置文件 $config = require 'config.php'; // 启动服务 try{ $server = new Server($config); $server->run(); }catch (\Throwable $exception){ var_dump($exception->getMessage(),$exception->getLine(),$exception->getFile()); }
其中配置文件config.php,内容如下:
<?php return [ /** 连接服务器的基本配置 */ 'server'=>[ 'host'=>'http://127.0.0.1:8848', 'username'=>'nacos', 'password'=>'nacos', ], /** 服务提供者实例的配置 */ 'instance'=>[ 'ip'=>'127.0.0.1', 'port'=>'8000', 'weight'=>100, ], /** 需要监听的配置 作为配置,你可能需要尽可能将配置合并到比较少的文件,一个项目一个配置文件最多两个配置文件就足够了。 */ 'config' => [ 'app' => [ # 是否开启监听 'enable' => true, 'dataId' => 'default', 'group' => 'default', # 需要配监听的配置文件 'file' => __DIR__ . '/application.yaml', # 监听到配置发生变化的回调 'callback' => function ($content) { file_put_contents(__DIR__ . "/application.yaml", $content); // todo 重新加载配置,刷新应用 } ], ], /** 需要注册的服务 */ 'service'=>[ // 服务标识:demo 'demo'=>[ 'enable'=>true, 'serviceName'=>\Xiaosongshu\Nacos\Samples\DemoService::class, 'namespace'=>'public', ], // 服务标识:login 'login' => [ 'enable' => true, 'serviceName' => \Xiaosongshu\Nacos\Samples\LoginService::class, // 实际实现类 'namespace' => 'public', # 契约 也就是功能映射,客户端只关心调用login功能,不关心具体是执行哪个方法 'contract' => [ 'out' => 'logout' ] ] ] ];
而服务提供者DemoService.php内容如下
<?php namespace Xiaosongshu\Nacos\Samples; /** * @purpose 示例服务提供者 * @author yanglong * @time 2025年7月25日12:16:19 */ class DemoService { /** * 示例方法:添加用户信息 * @param string $name 姓名 * @param int $age 年龄 * @return string */ public function add(string $name, int $age): string { return "用户添加成功!姓名:{$name},年龄:{$age}(服务端处理时间:" . date('H:i:s') . ")"; } /** * 示例方法:获取用户信息 * @param string $name 姓名 * @return array */ public function get(string $name): array { return [ 'name' => $name, 'age' => 25, 'message' => "查询成功(服务端时间:" . date('H:i:s') . ")" ]; } }
服务提供者LoginService.php内容如下:
<?php namespace Xiaosongshu\Nacos\Samples; /** * @purpose 用户登录服务 * @author yanglong * @time 2025年7月25日17:32:27 */ class LoginService { /** * 用户登录接口 * @param string $username 用户名(必填,长度≥3) * @param string $password 密码(必填,长度≥6) * @return array 登录结果,包含token */ public function login(string $username, string $password): array { // 模拟业务逻辑:验证用户名密码 if (strlen($username) < 3) { return ['success' => false, 'message' => '用户名长度不能少于3位']; } if (strlen($password) < 6) { return ['success' => false, 'message' => '密码长度不能少于6位']; } // 模拟生成token $token = md5($username . time() . 'secret'); return [ 'success' => true, 'message' => '登录成功', 'token' => $token, 'expire' => 3600 // token有效期(秒) ]; } /** * 退出登录 * @param string $token * @return array */ public function logout(string $token): array{ return [ 'success' => true, 'message' => '退出登录成功', 'token' => $token, ]; } }
编写完以上文件后,开启服务,命令如下:
php server.php
这个时候我们再编写一个客户端client.php,用来测试调用服务。内容如下:
<?php // 使用示例 require_once __DIR__ . '/vendor/autoload.php'; use Xiaosongshu\Nacos\JsonRpcClient; // Nacos配置(与服务端一致) $nacosConfig = [ 'host' => 'http://192.168.110.72:8848', 'username' => 'nacos', 'password' => 'nacos' ]; $client = new JsonRpcClient($nacosConfig); // 调用login服务(仅需传入服务标识和业务参数) $loginResult = $client->call('login', [ 'username' => 'zhangsan', 'password' => '123456' ]); // 打印结果 if ($loginResult['success']) { echo "登录成功:\n"; echo "Token:{$loginResult['result']['token']}\n"; echo "有效期:{$loginResult['result']['expire']}秒\n"; echo "调用实例:{$loginResult['instance']}\n"; } else { echo "登录失败:{$loginResult['error']}\n"; } // 退出登录 使用契约 $logoutRes = $client->call('login', ['token' => $loginResult['result']['token']], 'out'); if ($logoutRes['success']) { echo "退出登录成功:\n"; echo "Token:{$logoutRes['result']['token']}\n"; echo "调用实例:{$logoutRes['instance']}\n"; } else { echo "退出登录失败:{$logoutRes['error']}\n"; } // 3. 调用DemoService的add方法(添加用户) $addResult = $client->call( 'demo', // 服务标识(对应服务端配置中的serviceKey) [ 'name' => '张三', // 对应add方法的$name参数 'age' => 20 // 对应add方法的$age参数 ], 'add' // 要调用的方法名(DemoService的add方法) ); // 处理add方法结果 if ($addResult['success']) { echo "添加用户结果:{$addResult['result']}\n"; echo "调用的服务实例:{$addResult['instance']}\n\n"; } else { echo "添加用户失败:{$addResult['error']}\n\n"; } // 4. 调用DemoService的get方法(查询用户) $getResult = $client->call( 'demo', // 服务标识(不变) [ 'name' => '张三' // 对应get方法的$name参数 ], 'get' // 要调用的方法名(DemoService的get方法) ); // 处理get方法结果 if ($getResult['success']) { echo "查询用户结果:\n"; print_r($getResult['result']); // 打印数组结果 echo "调用的服务实例:{$getResult['instance']}\n"; } else { echo "查询用户失败:{$getResult['error']}\n"; }
现在需要启动客户端来测试服务是否可用。命令如下:
php client.php
那么服务端测试结果大概效果是这样子的
PS D:\php\nacosDemo> php .\server.php
[初始化] 已加载服务:demo -> Xiaosongshu\Nacos\Samples\DemoService(元数据解析完成)
[初始化] 已加载服务:login -> Xiaosongshu\Nacos\Samples\LoginService(元数据解析完成)
[初始化] 已加载配置:app -> D:\php\nacosDemo/application.yaml
[配置监听] 启动监听流:app(ID: 23) 2025-07-30 19:32:01
[Nacos] 已注册服务:demo -> SERVICE@@demo(IP:127.0.0.1:8000)
[Nacos] 已注册服务:login -> SERVICE@@login(IP:127.0.0.1:8000)
[初始化] 已发布配置:app(本地配置发布完毕)
[TCP服务] 已启动,监听:127.0.0.1:8000(JSON-RPC协议)
[心跳] 成功(demo)->Xiaosongshu\Nacos\Samples\DemoService(19:32:01)
[心跳] 成功(login)->Xiaosongshu\Nacos\Samples\LoginService(19:32:01)
[心跳] 成功(demo)->Xiaosongshu\Nacos\Samples\DemoService(19:32:06)
[心跳] 成功(login)->Xiaosongshu\Nacos\Samples\LoginService(19:32:06)
[心跳] 成功(demo)->Xiaosongshu\Nacos\Samples\DemoService(19:32:11)
[心跳] 成功(login)->Xiaosongshu\Nacos\Samples\LoginService(19:32:11)
[调试] 原始响应: default%02default%01 | 解码后: defaultdefault | 监听配置: dataId=default, group=default 2025-07-30 19:32:14
[config] app 配置发生变化(dataId: default, group: default) 2025-07-30 19:32:14
[配置监听] 启动监听流:app(ID: 38) 2025-07-30 19:32:16
[心跳] 成功(demo)->Xiaosongshu\Nacos\Samples\DemoService(19:32:16)
[心跳] 成功(login)->Xiaosongshu\Nacos\Samples\LoginService(19:32:16)
[心跳] 成功(demo)->Xiaosongshu\Nacos\Samples\DemoService(19:32:21)
[心跳] 成功(login)->Xiaosongshu\Nacos\Samples\LoginService(19:32:21)
[TCP] 新客户端连接:127.0.0.1:62536(clientId:43)
[TCP] 收到请求(127.0.0.1:62536):{"jsonrpc":"2.0","method":"login.login","params":["zhangsan","123456"],"id":"rpc_688a02c94b302"}
[TCP] 发送响应(127.0.0.1:62536):{"jsonrpc":"2.0","id":"rpc_688a02c94b302","result":{"success":true,"message":"登录成功","token":"4b650eac580d33294777cae55272609f","expire":3600}}
[TCP] 新客户端连接:127.0.0.1:62538(clientId:44)
[TCP] 客户端断开(127.0.0.1:62536)
[TCP] 收到请求(127.0.0.1:62538):{"jsonrpc":"2.0","method":"login.out","params":["4b650eac580d33294777cae55272609f"],"id":"rpc_688a02c9b5e31"}
[心跳] 成功(demo)->Xiaosongshu\Nacos\Samples\DemoService(19:32:26)
[心跳] 成功(login)->Xiaosongshu\Nacos\Samples\LoginService(19:32:26)
[TCP] 发送响应(127.0.0.1:62538):{"jsonrpc":"2.0","id":"rpc_688a02c9b5e31","result":{"success":true,"message":"退出登录成功","token":"4b650eac580d33294777cae55272609f"}}
[TCP] 新客户端连接:127.0.0.1:62548(clientId:47)
[TCP] 客户端断开(127.0.0.1:62538)
[TCP] 收到请求(127.0.0.1:62548):{"jsonrpc":"2.0","method":"demo.add","params":["张三",20],"id":"rpc_688a02ca2159f"}
[TCP] 发送响应(127.0.0.1:62548):{"jsonrpc":"2.0","id":"rpc_688a02ca2159f","result":"用户添加成功!姓名:张三,年龄:20(服务端处理时间:19:32:26)"}
[TCP] 新客户端连接:127.0.0.1:62549(clientId:48)
[TCP] 客户端断开(127.0.0.1:62548)
[TCP] 收到请求(127.0.0.1:62549):{"jsonrpc":"2.0","method":"demo.get","params":["张三"],"id":"rpc_688a02ca7a7a4"}
[TCP] 发送响应(127.0.0.1:62549):{"jsonrpc":"2.0","id":"rpc_688a02ca7a7a4","result":{"name":"张三","age":25,"message":"查询成功(服务端时间:19:32:26)"}}
[TCP] 客户端断开(127.0.0.1:62549)
[心跳] 成功(demo)->Xiaosongshu\Nacos\Samples\DemoService(19:32:31)
[心跳] 成功(login)->Xiaosongshu\Nacos\Samples\LoginService(19:32:31)
客户端的效果是这个样子的
PS D:\php\nacosServer> php .\client.php
登录成功:
Token:2d7b6bd23bd38d6051bf06a2d55c6eca
有效期:3600秒
调用实例:192.168.110.72:8000
退出登录成功:
Token:2d7b6bd23bd38d6051bf06a2d55c6eca
调用实例:192.168.110.72:8000
添加用户结果:用户添加成功!姓名:张三,年龄:20(服务端处理时间:18:52:47)
调用的服务实例:192.168.110.72:8000
查询用户结果:
Array
(
[name] => 张三
[age] => 25
[message] => 查询成功(服务端时间:18:52:47)
)
调用的服务实例:192.168.110.72:8000
以上代码亲测可用,当然你可能需要根据你的实际业务调整一下才行。
搭建nacos
docker run --name nacos -e MODE=standalone --env NACOS_AUTH_ENABLE=true -p 8848:8848 -p 31181:31181 -d nacos/nacos-server:1.3.1