三十九、Swoole 基础学习笔记 - Swoole 协程 HTTP/WebSocket 客户端

作者: 温新

分类: 【Swoole 系列】

阅读: 1432

时间: 2023-03-13 12:33:45

hi,我是温新,一名PHPer

文章基于 Swoole 5.0.1 版本编写。

学习目标:学习协程 HTTP/WebSocket 服务器

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

协程版 HTTP 客户端的底层用纯 C 编写,不依赖任何第三方扩展库,拥有超高的性能。

  • 支持 Http-ChunkKeep-Alive 特性,支持 form-data 格式;
  • HTTP 协议版本为 HTTP/1.1
  • 支持升级为 WebSocket 客户端;
  • gzip 压缩格式支持需要依赖 zlib 库;
  • 客户端仅实现核心的功能,实际项目建议使用 Saber。

演示案例

HTTP Server/Client

协程 http 服务端

<?php
// 39-swoole-coroutine-server.php

Swoole\Coroutine\run(function () {
    $http = new Swoole\Coroutine\Http\Server('0.0.0.0', 9502, false);
    $http->handle('/', function ($request, $response) {
        $response->end("<h1>Index</h1>");
    });
    $http->handle('/test', function ($request, $response) {
        $response->end("<h1>Test</h1>");
    });
    $http->handle('/stop', function ($request, $response) use ($http) {
        $response->end("<h1>Stop</h1>");
        $http->shutdown();
    });
    $http->start();
});

协程客户端

<?php
// 39-swoole-coroutine-http-server.php

Swoole\Coroutine\run(function () {
    $client = new Swoole\Coroutine\Http\Client('127.0.0.1', 9502);
    $client->setHeaders([
        'Host' => 'localhost',
        'User-Agent' => 'Chrome/49.0.2587.3',
        'Accept' => 'text/html,application/xhtml+xml,application/xml',
        'Accept-Encoding' => 'gzip',
    ]);
    $client->set(['timeout' => 1]);
    // 发送 GET 请求
    $client->get('/');
    // 获取请求数据
    echo $client->body;
    $client->close();
});

输出结果

$php 39-swoole-coroutine-http-client.php 
<h1>Index</h1>

WebSocket 客户端

websocket 服务端

<?php
// 39-swoole-websocket-server.php
$ws = new Swoole\WebSocket\Server('0.0.0.0', 9503);

$ws->on('Open', function ($ws, $request) {
    $ws->push($request->fd, "hello, welcome\n");
});

$ws->on('Message', function ($ws, $frame) {
    echo "Message: {$frame->data}\n";
    $ws->push($frame->fd, "server: {$frame->data}");
});

$ws->on('Close', function ($ws, $fd) {
    echo "client-{$fd} is closed\n";
});

$ws->start();

协程客户端

<?php
// 39-swoole-coroutine-websocket-client.php


Swoole\Coroutine\run(function () {
    $client = new Swoole\Coroutine\Http\Client('127.0.0.1', 9503);
    $ws = $client->upgrade('/');
    if ($ws) {
        while(true) {
            $client->push('hello');
            var_dump($client->recv());
            Swoole\Coroutine::sleep(0.1);
        }
    }
});

协程客户端 API 学习

__construct

含义:构造函数。

语法&参数:

Swoole\Coroutine\Http\Client::__construct(string $host, int $port, bool $ssl = false);

# 参数
$host:目标服务器主机地址;
$port:目标服务器主机端口;
$ssl:是否启用 ssl

set

含义:设置客户端参数。

语法&参数

Swoole\Coroutine\Http\Client->set(array $options);

# 参数
此方法与 Swoole\Client->set 接收的参数完全一致,可以参考 Swoole\Client->set;
此外,该 set 还增加了一些设置用于控制 HTTP 和 WebSocket 客户端。

额外选项

  • 超时时间(timeout);
  • 长连接(keep_alive);
  • websocket_maxk - 客户端启用或关闭掩码。

get

含义:发送 GET 请求。

语法&参数:

Swoole\Coroutine\Http\Client->get(string $path): void

# 参数
$path:设置 URL 路径【如 /index.html,注意这里不能传入 http://domain】

post

含义:发送 post 请求。

语法&参数:

Swoole\Coroutine\Http\Client->post(string $path, mixed $data): void

# 参数
$path:设置 URL 路径【如 /index.html,注意这里不能传入 http://domain】
$data:请求的包体数据

服务端代码修改

$http->handle('/test', function ($request, $response) {
    print_r($request->post);
    $response->end("<h1>Test</h1>");
});

客户端代码修改

Swoole\Coroutine\run(function () {
    $client = new Swoole\Coroutine\Http\Client('127.0.0.1', 9502);
    $client->post('/test', ['web_name'=>'自如初']);
    echo $client->body;
    $client->close();
});

upgrade

含义:升级为 WebSocket 连接。

语法&参数:

Swoole\Coroutine\Http\Client->upgrade(string $path): bool
    
# 参数
$path:设置 URL 路径【如 /,注意这里不能传入 http://domain】

注意:

1、某些情况下请求虽然是成功的,upgrade 返回了 true,但服务器并未设置 HTTP 状态码为 101,而是 200403,这说明服务器拒绝了握手请求;

2、WebSocket 握手成功后可以使用 push 方法向服务器端推送消息,也可以调用 recv 接收消息;

3、upgrade 会产生一次协程调度。

push

含义:向 WebSocket 服务器推送消息。

语法&参数:

Swoole\Coroutine\Http\Client->push(mixed $data, int $opcode = WEBSOCKET_OPCODE_TEXT, bool $finish = true): bool

# 参数
$data:要发送的数据内容【默认为 UTF-8 文本格式,如果为其他格式编码或二进制数据,请使用 WEBSOCKET_OPCODE_BINARY】
$opcode:操作类型
$finish:操作类型

rece

含义:接收消息。只为 WebSocket 使用,需要配合 upgrade() 使用。

语法&参数:

Swoole\Coroutine\Http\Client->recv(float $timeout = 0)
    
# 参数
$timeout:超时时间

download

含义:通过 HTTP 下载文件。

语法&参数:

Swoole\Coroutine\Http\Client->download(string $path, string $filename,  int $offset = 0): bool

# 参数
$path:设置 URL 路径
$filename:指定下载内容写入的文件路径【会自动写入到 downloadFile 属性】
$offset:功能:指定写入文件的偏移量【此选项可用于支持断点续传,可配合 HTTP 头 Range:bytes=$offset 实现】

setCookies

含义:设置 Cookie。

语法:Swoole\Coroutine\Http\Client->setCookies(array $cookies): void

getCookie

含义:获取 HTTP 响应的 cookie 内容。

语法:Swoole\Coroutine\Http\Client->getCookies(): array|false

案例:

Swoole\Coroutine\run(function () {
    $client = new Swoole\Coroutine\Http\Client('127.0.0.1', 9502);
    $client->setCookies(['age'=>19]);
    var_dump($client->getCookies());
    $client->close();
});

getBody

含义:获取 HTTP 响应的包体内容。

语法:Swoole\Coroutine\Http\Client->getBody(): string|false

close

含义:关闭连接。

语法:Swoole\Coroutine\Http\Client->close(): bool

函数:request()

含义:发起一个指定请求方式的请求。

函数:get()

含义:发起一个 get 请求

函数:post()

含义:发起一个 post 请求

案例:

Swoole\Coroutine\run(function () {
    $data1 = Swoole\Coroutine\Http\request('http://localhost:9502/test', 'get');
    $data2 = Swoole\Coroutine\Http\get('http://localhost:9502/test');
    $data3 = Swoole\Coroutine\Http\post('http://localhost:9502/test',[]);
});

我是温新,本篇文章结束。

请登录后再评论