Http\Server 继承自 Server,所以 Server 提供的所有 API 和配置项都可以使用,进程模型也是一致的。请参考 Server 章节。
内置 HTTP 服务器的支持,通过几行代码即可写出一个高并发,高性能,异步 IO 的多进程 HTTP 服务器。
$http = new Swoole\Http\Server("127.0.0.1", 9501);
$http->on('request', function ($request, $response) {
$response->end("<h1>Hello Swoole. #".rand(1000, 9999)."</h1>");
});
$http->start();通过使用 Apache bench 工具进行压力测试,在 Inter Core-I5 4核 + 8G内存的普通 PC 机器上,Http\Server 可以达到近 11万QPS。
远远超过 PHP-FPM、Golang、Node.js 自带 Http 服务器。性能几乎接近与 Nginx 的静态文件处理。
ab -c 200 -n 200000 -k http://127.0.0.1:9501/
使用 HTTP2 协议
使用 SSL 下的 HTTP2 协议必须安装 openssl, 且需要高版本 openssl 必须支持 TLS1.2、ALPN、NPN
编译时需要使用 --enable-http2 开启
./configure --enable-openssl --enable-http2
设置 HTTP 服务器的 open_http2_protocol 为 true
$server = new Swoole\Http\Server("127.0.0.1", 9501, SWOOLE_PROCESS, SWOOLE_SOCK_TCP | SWOOLE_SSL);
$server->set([
'ssl_cert_file' => $ssl_dir . '/ssl.crt',
'ssl_key_file' => $ssl_dir . '/ssl.key',
'open_http2_protocol' => true,
]);Nginx + Swoole 配置
由于 Http\Server 对 HTTP 协议的支持并不完整,建议仅作为应用服务器,用于处理动态请求,并且在前端增加 Nginx 作为代理。
server {
root /data/wwwroot/;
server_name local.swoole.com;
location / {
proxy_http_version 1.1;
proxy_set_header Connection "keep-alive";
proxy_set_header X-Real-IP $remote_addr;
if (!-e $request_filename) {
proxy_pass http://127.0.0.1:9501;
}
}
}通过读取 $request->header['x-real-ip'] 来获取客户端的真实 IP
注册事件回调函数。
与 Server 的回调 相同,不同之处是:
$http_server->on('request', function(\Swoole\Http\Request $request, \Swoole\Http\Response $response) {
$response->end("<h1>hello swoole</h1>");
});
在收到一个完整的 HTTP 请求后,会回调此函数。回调函数共有 2 个参数:
$request,HTTP 请求信息对象,包含了 header/get/post/cookie 等相关信息
$response,HTTP 响应对象,支持 cookie/header/status 等 HTTP 操作
在 onRequest 回调函数返回时底层会销毁 $request 和 $response 对象
启动 HTTP 服务器
启动后开始监听端口,并接收新的 HTTP 和 WebSocket 请求。
Swoole\Http\Server->start();
HTTP 请求对象,保存了 HTTP 客户端请求的相关信息,包括 GET、POST、COOKIE、Header 等。
请勿使用 & 符号引用 Http\Request 对象
HTTP 请求的头部信息。类型为数组,所有 key 均为小写。
Swoole\Http\Request->header: array
示例
echo $request->header['host'];
echo $request->header['accept-language'];
数组的 key 全部为小写,并且与 PHP 的 $_SERVER 数组保持一致
示例
echo $request->server['request_time'];
| key | 说明 |
|---|---|
| query_string | 请求的 GET 参数,如:id=1&cid=2 如果没有 GET 参数,该项不存在 |
| request_method | 请求方法,GET/POST 等 |
| request_uri | 无 GET 参数的访问地址,如 /favicon.ico |
| path_info | 同 request_uri |
| request_time | request_time 是在 Worker 设置的,在 SWOOLE_PROCESS 模式下存在 dispatch 过程,因此可能会与实际收包时间存在偏差。尤其是当请求量超过服务器处理能力时,request_time 可能远滞后于实际收包时间。可以通过 $server->getClientInfo 方法获取 last_time 获得准确的收包时间。 |
| request_time_float | 请求开始的时间戳,以微秒为单位,float 类型,如 1576220199.2725 |
| server_protocol | 服务器协议版本号,HTTP 是:HTTP/1.0 或 HTTP/1.1,HTTP2 是:HTTP/2 |
| server_port | 服务器监听的端口 |
| remote_port | 客户端的端口 |
| remote_addr | 客户端的 IP 地址 |
| master_time | 连接上次通讯时间 |
HTTP 请求的 GET 参数,相当于 PHP 中的 $_GET,格式为数组。
Swoole\Http\Request->get: array
示例
// 如:index.php?hello=123 echo $request->get['hello']; // 获取所有GET参数 var_dump($request->get);
注意
为防止 HASH 攻击,GET 参数最大不允许超过 128 个
HTTP 请求的 POST 参数,格式为数组
Swoole\Http\Request->post: array
示例
echo $request->post['hello'];
注意
-POST 与 Header 加起来的尺寸不得超过 package_max_length 的设置,否则会认为是恶意请求
-POST 参数的个数最大不超过 128 个
HTTP 请求携带的 COOKIE 信息,格式为键值对数组。
Swoole\Http\Request->cookie: array
示例
echo $request->cookie['username'];
上传文件信息。
类型为以 form 名称为 key 的二维数组。与 PHP 的 $_FILES 相同。最大文件尺寸不得超过 package_max_length 设置的值。请勿使用 Swoole\Http\Server 处理大文件上传。
Swoole\Http\Request->files: array
示例
Array ( [name] => facepalm.jpg // 浏览器上传时传入的文件名称 [type] => image/jpeg // MIME类型 [tmp_name] => /tmp/swoole.upfile.n3FmFr // 上传的临时文件,文件名以/tmp/swoole.upfile开头 [error] => 0 [size] => 15476 // 文件尺寸 )
注意
当 $request 对象销毁时,会自动删除上传的临时文件
Swoole 版本 >= v4.5.0 可用,在低版本可使用别名 rawContent (此别名将永久保留,即向下兼容)
获取原始的 POST 包体。
用于非 application/x-www-form-urlencoded 格式的 HTTP POST 请求。返回原始 POST 数据,此函数等同于 PHP 的 fopen('php://input')
Swoole\Http\Request->getContent(): string
有些情况下服务器不需要解析 HTTP POST 请求参数,通过 http_parse_post 配置,可以关闭 POST 数据解析。
获取完整的原始 Http 请求报文。包括 Http Header 和 Http Body
Swoole\Http\Request->getData(): string
创建一个 Swoole\Http\Request 对象。
Swoole 版本 >= v4.6.0 可用
Swoole\Http\Request->create(array $options): Swoole\Http\Request|false
参数
功能:可选参数,用于设置 Request 对象的配置
array $options
| 参数 | 默认值 | 说明 |
|---|---|---|
| parse_cookie | true | 设置是否解析 Cookie |
| parse_body | true | 设置是否解析 Http Body |
| parse_files | true | 设置上传文件解析开关 |
| enable_compression | true | 设置是否启用压缩 |
| compression_level | 1 | 设置压缩级别,范围是 1-9,等级越高压缩后的尺寸越小,但 CPU 消耗更多 |
解析 HTTP 请求数据包,会返回成功解析的数据包长度。
Swoole 版本 >= v4.6.0 可用
Swoole\Http\Request->parse(string $data): int|false
获取当前的 HTTP 请求数据包是否已到达结尾。
Swoole 版本 >= v4.6.0 可用
示例
use Swoole\Http\Request;
$data = "GET /index.html?hello=world&test=2123 HTTP/1.1\r\n";
$data .= "Host: 127.0.0.1\r\n";
$data .= "Connection: keep-alive\r\n";
$data .= "Pragma: no-cache\r\n";
$data .= "Cache-Control: no-cache\r\n";
$data .= "Upgrade-Insecure-Requests: \r\n";
$data .= "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36\r\n";
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\r\n";
$data .= "Accept-Encoding: gzip, deflate, br\r\n";
$data .= "Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7,ja;q=0.6\r\n";
$data .= "Cookie: env=pretest; phpsessid=fcccs2af8673a2f343a61a96551c8523d79ea; username=hantianfeng\r\n";
/** @var Request $req */
$req = Request::create(['parse_cookie' => false]);
var_dump($req);
var_dump($req->isCompleted());
var_dump($req->parse($data));
var_dump($req->parse("\r\n"));
var_dump($req->isCompleted());
var_dump($req);
// 关闭了解析cookie,所以会是null
var_dump($req->cookie);
获取当前的 HTTP 请求的请求方式。
Swoole 版本 >= v4.6.2 可用
var_dump($request->server['request_method']); var_dump($request->getMethod());
HTTP 响应对象,通过调用此对象的方法,实现 HTTP 响应发送。
当 Response 对象销毁时,如果未调用 end 发送 HTTP 响应,底层会自动执行 end("");
请勿使用 & 符号引用 Http\Response 对象
设置 HTTP 响应的 Header 信息【别名 setHeader】
Swoole\Http\Response->header(string $key, string $value, bool $format = true);
参数
功能:是否需要对 Key 进行 HTTP 约定格式化【默认 true 会自动格式化】
默认值:true
其它值:无
功能:HTTP 头的 value
默认值:无
其它值:无
功能:HTTP 头的 Key
默认值:无
其它值:无
string $key
string $value
bool $format
返回值
设置失败,返回 false
设置成功,没有任何返回值
注意
-header 设置必须在 end 方法之前 -$key 必须完全符合 HTTP 的约定,每个单词首字母大写,不得包含中文,下划线或者其他特殊字符
-$value 必须填写
-$ucwords 设为 true,底层会自动对 $key 进行约定格式化
- 重复设置相同 $key 的 HTTP 头会覆盖,取最后一次
Swoole 版本 >= v4.6.0 时,支持重复设置相同 $key 的 HTTP 头,并且 $value 支持多种类型,如 array、object、int、float,底层会进行 toString 转换,并且会移除末尾的空格以及换行。
$response->header('content-type', 'image/jpeg', true);
$response->header('Content-Length', '100002 ');
$response->header('Test-Value', [
"a\r\n",
'd5678',
"e \n ",
null,
5678,
3.1415926,
]);
$response->header('Foo', new SplFileInfo('bar'));将 Header 信息附加到 HTTP 响应的末尾,仅在 HTTP2 中可用,用于消息完整性检查,数字签名等。
Swoole\Http\Response->trailer(string $key, string $value, bool $ucwords = true);
参数
功能:是否需要对 Key 进行 HTTP 约定格式化【默认 true 会自动格式化】
默认值:true
其它值:无
功能:HTTP 头的 value
默认值:无
其它值:无
功能:HTTP 头的 Key
默认值:无
其它值:无
string $key
string $value
bool $ucwords
返回值
设置失败,返回 false
设置成功,没有任何返回值
注意
重复设置相同 $key 的 Http 头会覆盖,取最后一次。
示例
$response->trailer('grpc-status', 0);
$response->trailer('grpc-message', '');设置 HTTP 响应的 cookie 信息。别名 setCookie。此方法参数与 PHP 的 setcookie 一致。
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 = '');
注意
-cookie 设置必须在 end 方法之前
-$samesite 参数从 v4.4.6 版本开始支持,$priority 参数从 v4.5.8 版本开始支持
-Swoole 会自动会对 $value 进行 urlencode 编码,可使用 rawCookie() 方法关闭对 $value 的编码处理
-Swoole 允许设置多个相同 $key 的 COOKIE
设置 HTTP 响应的 cookie 信息
rawCookie() 的参数和上文的 cookie() 一致,只不过不进行编码处理
发送 Http 状态码。别名 setStatusCode()
Swoole\Http\Response->status(int $http_status_code, string $reason): bool
参数
功能:状态码原因
默认值:无
其它值:无
功能:设置 HttpCode
默认值:200
其它值:无
int $http_status_code
string $reason
提示
如果只传入了第一个参数 $http_status_code 必须为合法的 HttpCode,如 200、502、301、404 等,否则会设置为 200 状态码
如果设置了第二个参数 $reason,$http_status_code 可以为任意的数值,包括未定义的 HttpCode,如 499
必须在 $response->end() 之前执行 status 方法
此方法在 4.1.0 或更高版本中已废弃,请移步 http_compression;在新版本中使用 http_compression 配置项取代了 gzip 方法。
主要原因是 gzip() 方法未判断浏览器客户端传入的 Accept-Encoding 头,如果客户端不支持 gzip 压缩,强行使用会导致客户端无法解压。
全新的 http_compression 配置项会根据客户端 Accept-Encoding 头,自动选择是否压缩,并自动选择最佳的压缩算法。
启用 Http GZIP 压缩。压缩可以减小 HTML 内容的尺寸,有效节省网络带宽,提高响应时间。必须在 write/end 发送内容之前执行 gzip,否则会抛出错误。
Swoole\Http\Response->gzip(int $level = 1);
参数
功能:压缩等级,等级越高压缩后的尺寸越小,但 CPU 消耗更多。
默认值:1
其它值:1-9
int $level
调用 gzip 方法后,底层会自动添加 Http 编码头,PHP 代码中不应当再行设置相关 Http 头;jpg/png/gif 格式的图片已经经过压缩,无需再次压缩
gzip 功能依赖 zlib 库,在编译 swoole 时底层会检测系统是否存在 zlib,如果不存在,gzip 方法将不可用。可以使用 yum 或 apt-get 安装 zlib 库:
sudo apt-get install libz-dev
发送 Http 跳转。调用此方法会自动 end 发送并结束响应。
Swoole\Http\Response->redirect(string $url, int $http_code = 302): void
参数
功能:状态码【默认为 302 临时跳转,传入 301 表示永久跳转】
默认值:302
其它值:无
功能:跳转的新地址,作为 Location 头进行发送
默认值:无
其它值:无
string $url
int $http_code
示例
$http = new Swoole\Http\Server("0.0.0.0", 9501, SWOOLE_BASE);
$http->on('request', function ($req, Swoole\Http\Response $resp) {
$resp->redirect("http://www.baidu.com/", 301);
});
$http->start();启用 Http Chunk 分段向浏览器发送相应内容。
关于 Http Chunk 可以参考 Http 协议标准文档。
Swoole\Http\Response->write(string $data): bool
参数
功能:要发送的数据内容【最大长度不得超过 2M,受 buffer_output_size 配置项控制】
默认值:无
其它值:无
string $data
提示
使用 write 分段发送数据后,end 方法将不接受任何参数,调用 end 只是会发送一个长度为 0 的 Chunk 表示数据传输完毕。
发送文件到浏览器。
Swoole\Http\Response->sendfile(string $filename, int $offset = 0, int $length = 0): bool
参数
功能:发送数据的尺寸
默认值:文件的尺寸
其它值:无
功能:上传文件的偏移量【可以指定从文件的中间部分开始传输数据。此特性可用于支持断点续传】
默认值:0
其它值:无
功能:要发送的文件名称【文件不存在或没有访问权限 sendfile 会失败】
默认值:无
其它值:无
string $filename
int $offset
int $length
提示
底层无法推断要发送文件的 MIME 格式因此需要应用代码指定 Content-Type
调用 sendfile 前不得使用 write 方法发送 Http-Chunk
调用 sendfile 后底层会自动执行 end
sendfile 不支持 gzip 压缩
示例
$response->header('Content-Type', 'image/jpeg');
$response->sendfile(__DIR__.$request->server['request_uri']);发送 Http 响应体,并结束请求处理。
Swoole\Http\Response->end(string $html): bool
参数
功能:要发送的内容
默认值:无
其它值:无
string $html
提示
end 只能调用一次,如果需要分多次向客户端发送数据,请使用 write 方法
客户端开启了 KeepAlive,连接将会保持,服务器会等待下一次请求
客户端未开启 KeepAlive,服务器将会切断连接
end 要发送的内容,由于受到 output_buffer_size 的限制,默认为 2M,如果大于这个限制则会响应失败,并抛出如下错误:
解决方法为:使用 sendfile、write 或调整 output_buffer_size
WARNING finish (ERRNO 1203): The length of data [262144] exceeds the output buffer size[131072], please use the sendfile, chunked transfer mode or adjust the output_buffer_size
分离响应对象。使用此方法后,$response 对象销毁时不会自动 end,与 Http\Response::create 和 Server->send 配合使用。
Swoole\Http\Response->detach(): bool
示例
某些情况下,需要在 Task 进程中对客户端发出响应。这时可以利用 detach 使 $response 对象独立。在 Task 进程可以重新构建 $response,发起 Http 请求响应。
跨进程响应
$http = new Swoole\Http\Server("0.0.0.0", 9501);
$http->set(['task_worker_num' => 1, 'worker_num' => 1]);
$http->on('request', function ($req, Swoole\Http\Response $resp) use ($http) {
$resp->detach();
$http->task(strval($resp->fd));
});
$http->on('finish', function () {
echo "task finish";
});
$http->on('task', function ($serv, $task_id, $worker_id, $data) {
var_dump($data);
$resp = Swoole\Http\Response::create($data);
$resp->end("in task");
echo "async task\n";
});
$http->start();发送任意内容
某些特殊的场景下,需要对客户端发送特殊的响应内容。Http\Response 对象自带的 end 方法无法满足需求,可以使用 detach 分离响应对象,然后自行组装 HTTP 协议响应数据,并使用 Server->send 发送数据。
$http = new Swoole\Http\Server("0.0.0.0", 9501);
$http->on('request', function ($req, Swoole\Http\Response $resp) use ($http) {
$resp->detach();
$http->send($resp->fd, "HTTP/1.1 200 OK\r\nServer: server\r\n\r\nHello World\n");
});
$http->start();
构造新的 Swoole\Http\Response 对象。
使用此方法前请务必调用 detach 方法将旧的 $response 对象分离,否则可能会造成对同一个请求发送两次响应内容。
Swoole\Http\Response::create(int $fd): Swoole\Http\Response
调用成功返回一个新的 Http\Response 对象,调用失败返回 false
参数
功能:参数为需要绑定的连接 $fd【调用 Http\Response 对象的 end 与 write 方法时会向此连接发送数据】
默认值:无
其它值:无
int $fd
示例
$http = new Swoole\Http\Server('0.0.0.0', 9501);
$http->on('request', function ($req, Swoole\Http\Response $resp) use ($http) {
$resp->detach();
$resp2 = Swoole\Http\Response::create($req->fd);
$resp2->end("hello world");
});
$http->start();判断 Swoole\Http\Response 对象是否已结束 (end) 或已分离 (detach)。
Swoole\Http\Response->isWritable(): bool
Swoole 版本 >= v4.6.0 可用
示例
use Swoole\Http\Server;
use Swoole\Http\Request;
use Swoole\Http\Response;
$http = new Server('0.0.0.0', 9501);
$http->on('request', function (Request $req, Response $resp) {
var_dump($resp->isWritable()); // true
$resp->end('hello');
var_dump($resp->isWritable()); // false
$resp->setStatusCode(403); // http response is unavailable (maybe it has been ended or detached)
});
$http->start();设置上传文件的临时目录。目录最大长度不得超过 220 字节
$server->set([ 'upload_tmp_dir' => '/data/uploadfiles/', ]);
针对 Request 对象的配置,设置 POST 消息解析开关,默认开启
设置为 true 时自动将 Content-Type为x-www-form-urlencoded 的请求包体解析到 POST 数组。
设置为 false 时将关闭 POST 解析。
$server->set([ 'http_parse_post' => false, ]);
针对 Request 对象的配置,关闭 Cookie 解析,将在 header 中保留未经处理的原始的 Cookies 信息。默认开启
$server->set([ 'http_parse_cookie' => false, ]);
针对 Request 对象的配置,设置上传文件解析开关。默认开启
$server->set([ 'http_parse_files' => false, ]);
针对 Response 对象的配置,启用压缩。默认为开启。
-http-chunk 不支持分段单独压缩,若使用 write 方法,将会强制关闭压缩。
-http_compression 在 v4.1.0 或更高版本可用
$server->set([ 'http_compression' => false, ]);
目前支持 gzip、br、deflate 三种压缩格式,底层会根据浏览器客户端传入的 Accept-Encoding 头自动选择压缩方式。
依赖:
gzip 和 deflate 依赖 zlib 库,在编译 Swoole 时底层会检测系统是否存在 zlib。
可以使用 yum 或 apt-get 安装 zlib 库:
sudo apt-get install libz-dev
br 压缩格式依赖 google 的 brotli 库,安装方式请自行搜索 install brotli on linux,在编译 Swoole 时底层会检测系统是否存在 brotli。
压缩级别,针对 Response 对象的配置
$level 压缩等级,范围是 1-9,等级越高压缩后的尺寸越小,但 CPU 消耗更多。默认为 1, 最高为 9
配置静态文件根目录,与 enable_static_handler 配合使用。
此功能较为简易,请勿在公网环境直接使用
$server->set([ 'document_root' => '/data/webroot/example.com', // v4.4.0以下版本, 此处必须为绝对路径 'enable_static_handler' => true, ]);
设置 document_root 并设置 enable_static_handler 为 true 后,底层收到 Http 请求会先判断 document_root 路径下是否存在此文件,如果存在会直接发送文件内容给客户端,不再触发 onRequest 回调。
使用静态文件处理特性时,应当将动态 PHP 代码和静态文件进行隔离,静态文件存放到特定的目录
开启静态文件请求处理功能,需配合 document_root 使用 默认 false
开启 http autoindex 功能 默认不开启
配合 http_autoindex 使用,指定需要被索引的文件列表
$server->set([ 'document_root' => '/data/webroot/example.com', 'enable_static_handler' => true, 'http_autoindex' => true, 'http_index_files' => ['indesx.html', 'index.txt'], ]);
设置静态处理器的路径。类型为数组,默认不启用。
Swoole 版本 >= v4.4.0 可用
$server->set([ 'static_handler_locations' => ['/static', '/app/images'], ]);
类似于 Nginx 的 location 指令,可以指定一个或多个路径为静态路径。只有 URL 在指定路径下才会启用静态文件处理器,否则会视为动态请求。
location 项必须以 / 开头
支持多级路径,如 /app/images
启用 static_handler_locations 后,如果请求对应的文件不存在,将直接返回 404 错误
启用 HTTP2 协议解析【默认值:false】
需要编译时启用 --enable-http2 选项
设置开启压缩的最小字节,超过该选项值才开启压缩。
Swoole 版本 >= v4.6.3 可用
$server->set([ 'compression_min_length' => 128, ]);