🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 路由 涉及到ClientData,PackTool,RouteTool # ClientData ClientData是ESD抽象出来的请求模型,这个模型针对任何协议。也就是说无论是TCP,HTTP,WS等等,所有的请求都必须封装成ClientData。 ~~~ /** * @var string */ protected $controllerName; /** * @var string */ protected $requestMethod; /** * @var string */ protected $methodName; /** * @var ClientInfo */ protected $clientInfo; /** * @var Request */ protected $request; /** * @var Response */ protected $response; /** * @var int */ protected $fd; /** * @var string */ protected $path; /** * @var array */ protected $params; /** * @var array */ protected $data; /** * @var mixed */ protected $responseRaw; ~~~ 其中比较重要的是 * controllerName 路由到的Controller类名 * methodName 理由到的方法名 * path 请求路径(无论什么协议都得有请求路径,即使是虚拟的) * params 访问方法时的参数 * data 数据内容 * requestMethod 请求方法,那么相对Http来说就是get,post之类的 还有些其他的方法一般是特定专用的。 # PackTool PackTool是协议自动解包/压包工具,目前提供的有NonJsonPack,LenJsonPack,EofJsonPack,具体的看代码不一一介绍了。 上面说的ClientData是路由的关键信息,那么PackTool就是用来生成ClientData的。 这里以NonJsonPack为例,这个提供了WS下无包头的json解析。 由于Websocket有自己的协议格式所以我们不需要定义包头,我们来看看NonJsonPack。 ~~~ public function encode(string $buffer) { return; } public function decode(string $buffer) { return; } ~~~ encode和decode是解析包头的,这里不需要直接返回。 ~~~ /** * @param $data * @param PortConfig $portConfig * @param string|null $topic * @return false|string */ public function pack($data, PortConfig $portConfig, ?string $topic = null) { return json_encode($data, JSON_UNESCAPED_UNICODE); } /** * @param int $fd * @param string $data * @param PortConfig $portConfig * @return ClientData * @throws \ESD\Core\Plugins\Config\ConfigException */ public function unPack(int $fd, string $data, PortConfig $portConfig): ?ClientData { $value = json_decode($data, true); if (empty($value)) { $this->warn('json unPack 失败'); return null; } $clientData = new ClientData($fd, $portConfig->getBaseType(), $value['p'], $value); return $clientData; } ~~~ pack就是一个json打包的过程。 unpack是解包生成ClientData的过程,ClientData的构造方法如下: ~~~ public function __construct($fd, $requestMethod, $path, $data) ~~~ 可以看出path源自请求时的json对象中的p字段。 # RouteTool 接下来就到了RouteTool了,默认框架是AnnotationRoute,其实里面是用FastRoute实现的。 那么刚才我们设置的ClientData的path字段在这里就要发挥作用了。 你可以把path当做http的url比如“test/abc”,这样其实更好理解,那么下一步就是写对应的Controller了,基本上和Http是一样的。找到路由后,会自动设置ClientData的ControllerName和MethodName。 ~~~ case Dispatcher::FOUND: // 找到对应的方法 $handler = $routeInfo[1]; // 获得处理函数 $vars = $routeInfo[2]; // 获取请求参数 $this->clientData->setControllerName($handler[0]->name); $this->clientData->setMethodName($handler[1]->name); ~~~ 关于WS的Controller怎么写,看下面的例子: ~~~ /** * @WsController() * Class CUser * @package ESD\Examples\Controller */ class WebSocket extends GoController { /** * RequestMapping() * @return string */ public function wsBindUid() { $this->bindUid($this->clientData->getFd(), "test1"); return "test"; } /** * @RequestMapping() * @return mixed|null */ public function wsGetUid() { return $this->getFdUid($this->clientData->getFd()); } /** * @RequestMapping() */ public function send() { $this->sendToUid("test1", "hello"); } /** * @RequestMapping() * @throws \ESD\Plugins\ProcessRPC\ProcessRPCException */ public function wsAddSub() { $this->addSub("sub", $this->getUid()); } /** * @RequestMapping() * @throws \ESD\Plugins\ProcessRPC\ProcessRPCException */ public function wsPub() { $this->pub("sub", "sub"); } } ~~~ 和Http的区别在于注解使用了@WsController而不是@RestController,相对的方法上的注解使用了@RequestMapping。 下面是ws对应的请求json: ```json {"p":"send","xxx":"xxx"} ``` # 总结 PackTool -> ClientData -> RouteTool HTTP是不需要PackTool的,因为Swoole帮我们解析成了Request和Response。