swoole http 客户端

文件结构

复制代码
>ls -lR
total 0
drwxrwxrwx 1 root root 512 Jan 14 16:19 client
drwxrwxrwx 1 root root 512 Jan 15 10:42 public
drwxrwxrwx 1 root root 512 Jan 15 10:21 server
drwxrwxrwx 1 root root 512 Jan 15 01:12 test

./client:
total 8
-rwxrwxrwx 1 root root 367 Jan 14 10:13 tcp_client.php
-rwxrwxrwx 1 root root 745 Jan 14 17:08 tcp_client_2.php
-rwxrwxrwx 1 root root 367 Jan 14 10:13 udp_client.php
-rwxrwxrwx 1 root root 911 Jan 14 17:05 udp_client_2.php

./public:
total 0
-rwxrwxrwx 1 root root 226 Jan 15 10:42 index.html

./server:
total 16
-rwxrwxrwx 1 root root 6360 Jan 17 07:37 http_server.php
-rwxrwxrwx 1 root root  730 Jan 14 10:09 tcp_server.php
-rwxrwxrwx 1 root root  665 Jan 14 16:35 udp_server.php

定义常量

php 复制代码
define('DS', DIRECTORY_SEPARATOR);
defined('SERVER_PATH') or define('SERVER_PATH', __DIR__ . DS);
defined('FILES_PATH') or define('FILES_PATH', dirname(realpath(SERVER_PATH)) . DS);
defined('PUBLIC_PATH') or define('PUBLIC_PATH', FILES_PATH . "public" . DS);

定义监听

php 复制代码
$address = "0.0.0.0";
$part = "80";

$http = new Server($address, $part);
$http->set(['task_worker_num' => 1, 'worker_num' => 1]);
$app = new Application();
$http->set([
    'document_root' => PUBLIC_PATH,
    'enable_static_handler' => true,
    'http_autoindex' => true,
    'http_index_files' => ['index.html', 'index.txt'],
]);
// $http->on('request', [$app, "OnRequest"]);
$http->on('request', function ($request, $reponse) use ($http) {
    $app = new Application();
    $parseInfo = $app->parsePathInfo($request);
    if (1 == $parseInfo['isdetach']) {
        $reponse->detach();
        $http->task(strval($reponse->fd));
    } else {
        $app->OnRequest($request, $reponse, $parseInfo);
    }
});
$http->on('task', function ($serv, $task_id, $worker_id, $data) {
    $resp = Response::create($data);
    $resp->write("task");
    $resp->end();
    $isWritable = empty($resp->isWritable()) ? 0 : 1;
    var_dump('isWritable:' . $isWritable);
    echo "async task\n";
});
$http->start();

解析请求数据,解析方法在Application::parsePathInfo中。

请求路径第一个数据为detach则使用$reponse->detach()创建task,在task线程中执行逻辑。

使用task进程,必须设置worker进程后开启该进程,默认不开启worker进程。

定义Application类

php 复制代码
class Application {
    private function setReponseHeader($request, $reponse) {
        $reponse->header('Content-Type', 'application/json; charset=utf-8');
        $reponse->header('access-control-allow-credentials', 'true');
        $reponse->header('access-control-allow-methods', 'GET,HEAD,POST,OPTIONS');
        $reponse->header('access-control-allow-headers', 'content-type,Authorization');
        $reponse->header('Access-Control-Allow-Private-Network', 'true');
        $origin = empty($request->header['origin']) ? '*' : $request->header['origin'];
        $reponse->header('access-control-allow-origin', $origin);
    }
    public function OnRequest($request, $reponse, $parseInfo = null) {
        $this->doredirect($request, $reponse);
        $param = $this->getparam($request);
        try {
            $this->setReponseHeader($request, $reponse);
            if (empty($parseInfo)) {
                $parseInfo = $this->parsePathInfo($request);
            }
            $data = $this->execFunction($parseInfo['controller'], $parseInfo['function'], $param);
            $reponse->end($data);
        } catch (\Throwable $th) {
            $code = $th->getCode();
            $msg = $th->getMessage();
            $data = backjson($code, $msg);
            $reponse->end($data);
        }
    }
    public function parsePathInfo($request) {
        $uri = $request->server['request_uri'];
        $uri_arr = array_values(array_filter(explode("/", $uri)));
        $isdetach = 0;
        if (2 == count($uri_arr)) {
            $c = ucfirst($uri_arr[0]) . "Controller";
            $f = $uri_arr[1];
            if (!class_exists($c)) {
                throw new \Exception("class " . $c . " not found", UseError::$SYSTEM_ERR);
            }
            if (!method_exists($c, $f)) {
                throw new \Exception("function " . $c . "::" . $f . " not found", UseError::$SYSTEM_ERR);
            }
            $data = [
                'uri' => $uri,
                'isdetach' => $isdetach,
                'controller' => $c,
                'function' => $f,
            ];
            return $data;
        } else {
            if ('detach' == $uri_arr[0]) {
                $isdetach = 1;
                $c = ucfirst($uri_arr[1]) . "Controller";
                $f = $uri_arr[2];
            }
            $data = [
                'uri' => $uri,
                'isdetach' => $isdetach,
                'controller' => $c,
                'function' => $f,
            ];
            return $data;
        }
        throw new \Exception("request_uri error", UseError::$SYSTEM_ERR);
    }
    private function doredirect($request, $reponse) {
        $uri = $request->server['request_uri'];
        if ('/baidu' == $uri) {
            $reponse->redirect("http://www.baidu.com/", 301);
        }
    }
    private function getparam($request) {
        $method = $request->getMethod();
        if ('GET' == $method) {
            $param = $request->get;
        } elseif ("POST" == $method) {
            $param = $request->post;
        }
        return $param;
    }

    public function execFunction($controller, $function, $param = []) {
        $object = new $controller();
        $reflection = new ReflectionClass($object);
        $method = $reflection->getMethod($function);
        $neddparams = $method->getParameters();
        if (count($neddparams) > 0) {
            $name_arr = [];
            foreach ($neddparams as $key => $value) {
                $name = $value->getName();
                $isOptional = $value->isOptional();
                $name_arr[] = $name;
                if (!isset($param[$name]) && !$isOptional) {
                    throw new \Exception("param " . $name . " is null", UseError::$SYSTEM_ERR);
                }
            }
            foreach ($param as $key => $value) {
                if (!in_array($key, $name_arr)) {
                    unset($param[$key]);
                }
            }
        } else {
            $param = [];
        }
        $reault = $method->invokeArgs($object, $param);
        return $reault;
    }
}

Application类中判断请求路径是否符合跳转条件,类似于反代理。

反代理解析Controller类。

IndexController类

php 复制代码
Class IndexController {
    public function hello() {
        $data = [
            "msg" => "hello word",
        ];
        return backjson(200, "success", $data);
    }

    public function test($name) {
        $data = [
            "msg" => "hello " . $name,
        ];
        return backjson(200, "success", $data);
    }

}

定义Error类

php 复制代码
class UseError {
    public static $SYSTEM_ERR = 500;
}
相关推荐
(Charon)11 小时前
【C++/Qt】Qt 实现 HTTP 测试工具:从请求构思到 GET/POST 实现
c++·qt·http
灰子学技术11 小时前
Envoy HTTP 协议实现技术文档
网络·网络协议·http
Lucis__11 小时前
HTTP协议深度解析—从HTTP原理到手写实现服务器
服务器·网络协议·http
pengyi87101512 小时前
代理IP选型优化,从源头降低HTTP代理延迟
网络协议·tcp/ip·http
灰子学技术1 天前
Envoy HTTP 过滤器处理技术文档
网络·网络协议·http
时空自由民.1 天前
HTTP协议和HTTPS协议结合天气获取案例介绍
网络协议·http·https
时空自由民.1 天前
HTTP协议帧格式
网络·网络协议·http
Rust研习社2 天前
使用 Axum 构建高性能异步 Web 服务
开发语言·前端·网络·后端·http·rust
灰子学技术2 天前
Envoy HTTP 流量层面的 Metric 指标分析
网络·网络协议·http