四、Swoole 基础学习笔记 - 启动一个 Swoole HTTP 服务器

作者: 温新

分类: 【Swoole 系列】

阅读: 1699

时间: 2023-01-11 12:46:03

4、Swoole 基础学习笔记 - 启动一个 Swoole HTTP 服务器

hi,我是温新,一名PHPer

文章基于 Swoole 5.0 版本编写。

学习目标:学习 Swoole Http Server 及相关知识。

说明:本篇文章结合官方文档编写及参考网络资料编写,虽非全部原创,但也是结合了自己的理解,若转载请附带本文 URL,编写不易,持续编写更不易,谢谢!

经过上一篇文章的洗刷后,我们再来看看 Swoole 的另一个功能——HTTP服务器,跑一个 HTTP 服务器来环境来缓解一下气氛。

Swoole 内置实现了一个简单的 HttpServer 类,相当于 php-fmp,其优势在于高性能,将代码载入内存,后续无需解释执行。由于 Http\ServerHTTP 协议的支持并不完整,建议仅作为应用服务器,用于处理动态请求,并且在前端增加 Nginx 作为代理。在实际生产环境中,在前端增加一层 Nginx,一些静态文件(css/js)等交给 Nginx,而 PHP 文件则交给 Swoole 来处理。

Swoole http 是如何处理请求的

来看看流程图,如下:

1、Http/Server 在协议解析部分使用的是 Http 协议;

2、http 协议请求会被封装中 Swoole\Http\Request 对象中,如请求参数,要从这里获取;

3、所有的 http 响应都要通过 Swoole\Http\Response 对象进程封装和发送。

学习了这些,再来看看运行 http server。

先把 Web 服务器运行起来

他用 swoole 创建一个异步非阻塞多进程的 Http 服务器。

<?php
// 2-swoole-http.php
    
// 实例化 http server 对象
$http = new Swoole\Http\Server('0.0.0.0', 9501);

// 监听网络请求
$http->on('Request', function ($request, $response) {
    // 处理/响应请求
    $response->header('Content-Type', 'text/html; charset=utf-8');
    $response->end('<h1>Hello Swoole. #' . rand(1000, 9999) . '</h1>');
});

// 启动 http server
$http->start();

解读一下代码,通过 Swoole\Http\Server 传递两个参数,实例化出一个 http 对象,然后监听 Request ,其回调函数接收两个参数,Swoole\Http\Request(请求) Swoole\Http\Response (响应)。如下是官方说明:

HTTP 服务器只需要关注请求响应即可,所以只需要监听一个 onRequest 事件。当有新的 HTTP 请求进入就会触发此事件。事件回调函数有 2 个参数,一个是 $request 对象,包含了请求的相关信息,如 GET/POST 请求的数据。

另外一个是 response 对象,对 request 的响应可以通过操作 response 对象来完成。$response->end() 方法表示输出一段 HTML 内容,并结束此请求。

现在请求服务,并在浏览器中输入 localhost:9501 就可以看到页面信息了。

运行 Swoole Http 还远远不够

http 协议有两个动作:请求响应,Swoole Http Server 也是如此。服务器运行起来后,该如何处理这两个动作?下面继续学习。

Swoole/Http/Request

作用:负责处理 http 请求的相关信息。

既然知道了 request 是处理请求相关的,那么它有哪些内容?现在把 $request 打印出来看看,它是什么:

// 省略其他内容
$http->on('Request', function ($request, $response) {
    print_r($request);
    // ...
});
// ...

通过打印的结果,可以看到它是一个 Swoole\Http\Request Object 对象,这个对象中包含了很多信息,有 header、server、cookie、get、post、files 等,

Swoole\Http\Request Object
(
    [fd] => 1
    [streamId] => 0
    [header] => Array
        (
            [host] => localhost:9501
            [connection] => keep-alive
            [sec-ch-ua] => "Google Chrome";v="107", "Chromium";v="107", "Not=A?Brand";v="24"
            [sec-ch-ua-mobile] => ?0
            [user-agent] => Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36
            [sec-ch-ua-platform] => "Linux"
            [accept] => image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8
            [sec-fetch-site] => same-origin
            [sec-fetch-mode] => no-cors
            [sec-fetch-dest] => image
            [referer] => http://localhost:9501/
            [accept-encoding] => gzip, deflate, br
            [accept-language] => zh-CN,zh;q=0.9
        )

    [server] => Array
        (
            [request_method] => GET
            [request_uri] => /favicon.ico
            [path_info] => /favicon.ico
            [request_time] => 1669652656
            [request_time_float] => 1669652656.2447
            [server_protocol] => HTTP/1.1
            [server_port] => 9501
            [remote_port] => 56526
            [remote_addr] => 127.0.0.1
            [master_time] => 1669652656
        )

    [cookie] => 
    [get] => 
    [files] => 
    [post] => 
    [tmpfiles] => 
)

想想以前接收 get 请求参数是使用 $_GET,而在 Swoole 中,这些超全局变量全部失效。以下是官方说明:

协程使得原有的异步逻辑同步化,但是在协程的切换是隐式发生的,所以在协程切换的前后不能保证全局变量以及 static 变量的一致性。

PHP-FPM下可以通过全局变量获取到请求的参数,服务器的参数等,在 Swoole 内,无法 通过 $_GET/$_POST/$_REQUEST/$_SESSION/$_COOKIE/$_SERVER$_开头的变量获取到任何属性参数。

在 Swoole 中,可以使用如下方式处理请求:

$_GET    = $request->get;
$_POST   = $request->post;
$_HEADER = $request->header;
$_SERVER = $request->server;
$_COOKIE = $request->cookie;
$_FILES  = $request->files;
$_CONTENT = $request->rawContent;
$request->getData;

转换一个方式就很好理解了,这种方式不用多说,相信 PHPer 都已经非常熟悉了,下面了解一下注意事项,然后动手试试吧。

  • 1、Swoole Http/Server 可以接收 application/x-www-form-urlencodedform-data 数据,解析后数据会放在 $request 对象中。若是 application/json 数据,需要通过 getContent() 方法来接收;
  • 2、Post 上传文件时,需要设置临时文件位置且需要设置包的大小,文件最大尺寸受到package_max_length 限制,不上传大文件进行处理。当 $request 对象销毁时,会自动删除上传的临时文件。

Swoole/Http/Response

**作用:负责响应 http 请求。**响应信息包含:响应头信息、响应状态等,没有列出的方法请参考官方文档。

Swoole\Http\Response->header(string $key, string $value, bool $format = true);
Swoole\Http\Response->cookie(string $key, string $value = '', int $expire = 0 , string $path = '/', string $domain  = '', bool $secure = false , bool $httponly = false, string $samesite = '', string $priority = '');
Swoole\Http\Response->status(int $http_status_code, string $reason): bool

压测 Swoole Http Server

了解了这么多,现在来看我们这服务进行压测看看,结果如下:

$ab -n 1000 -c 100  http://localhost:9501/

Server Software:        swoole-http-server
Server Hostname:        localhost
Server Port:            9501

Document Path:          /
Document Length:        28 bytes

Concurrency Level:      100
Time taken for tests:   0.030 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      191000 bytes
HTML transferred:       28000 bytes
Requests per second:    33518.80 [#/sec] (mean)
Time per request:       2.983 [ms] (mean)
Time per request:       0.030 [ms] (mean, across all concurrent requests)
Transfer rate:          6252.04 [Kbytes/sec] received

本篇文章到此结束,我是温新,我们下一篇文章见。

请登录后再评论