Http\Server
?> Http\Server
对Http
协议的支持并不完整,一定要作为应用服务器处理动态请求。并且在前端增加Nginx
作为代理
?> 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配置
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
on()
?> 注册事件回调函数。
?> 与 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
对象
start()
?> 启动Http服务器
?> 启动后开始监听端口,并接收新的Http
和WebSocket
请求。
Swoole\Http\Server->start();
Http\Request
Http
请求对象,保存了Http
客户端请求的相关信息,包括GET
、POST
、COOKIE
、Header
等。
!> 请勿使用&
符号引用Http\Request
对象
header
?> Http
请求的头部信息。类型为数组,所有key
均为小写。
Swoole\Http\Request->header: array;
- 示例
echo $request->header['host'];
echo $request->header['accept-language'];
server
?> Http
请求相关的服务器信息。
?> 相当于PHP
的$_SERVER
数组。包含了Http
请求的方法,URL
路径,客户端IP
等信息。
Swoole\Http\Request->server: array;
数组的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 | 连接上次通讯时间 |
get
?> 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
个
post
?> HTTP
POST
参数,格式为数组
Swoole\Http\Request->post: array;
- 示例
echo $request->post['hello'];
- 注意
!> -POST
与Header
加起来的尺寸不得超过package_max_length的设置,否则会认为是恶意请求
-POST
参数的个数最大不超过128
个
cookie
?> HTTP
请求携带的COOKIE
信息,格式为键值对数组。
Swoole\Http\Request->cookie: array;
- 示例
echo $request->cookie['username'];
files
?> 上传文件信息。
?> 类型为以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开头
[size] => 15476 // 文件尺寸
[error] => 0
)
- 注意
!> 当$request
对象销毁时,会自动删除上传的临时文件
rawContent()
?> 获取原始的POST
包体。
?> 用于非application/x-www-form-urlencoded
格式的Http
POST
请求。返回原始POST
数据,此函数等同于PHP
的fopen('php://input')
Swoole\Http\Request->rawContent(): string;
提示
- 有些情况下服务器不需要解析
Http
POST
请求参数,通过http_parse_post 配置,可以关闭POST
数据解析。
- 有些情况下服务器不需要解析
getData()
?> 获取完整的原始Http
请求报文。包括Http Header
和Http Body
Swoole\Http\Request->getData(): string;
Http\Response
Http
响应对象,通过调用此对象的方法,实现Http
响应发送。
?> 当Response
对象销毁时,如果未调用end发送Http
响应,底层会自动执行end("")
;
!> 请勿使用&
符号引用Http\Response
对象
header()
?> 设置HTTP响应的Header信息
Swoole\Http\Response->header(string $key, string $value, bool $ucwords = true);
参数
string $key
- 功能:
Http
头的Key
- 默认值:无
- 其它值:无
- 功能:
string $value
- 功能:
Http
头的value
- 默认值:无
- 其它值:无
- 功能:
string $ucwords
- 功能: 是否需要对
Key
进行Http
约定格式化【默认true
会自动格式化】 - 默认值:
true
- 其它值:无
- 功能: 是否需要对
返回值
- 设置失败,返回
false
- 设置成功,没有任何返回值
- 设置失败,返回
注意
-
header
设置必须在end
方法之前 -$key
必须完全符合Http
的约定,每个单词首字母大写,不得包含中文,下划线或者其他特殊字符
-$value
必须填写
-$ucwords
设为true
,底层会自动对$key
进行约定格式化- 重复设置相同
$key
的Http
头会覆盖,取最后一次。
- 重复设置相同
示例
$response->header('content-type', 'image/jpeg', true);
trailer()
?> 将Header
信息附加到HTTP
响应的末尾,仅在HTTP2
中可用,用于消息完整性检查,数字签名等。
Swoole\Http\Response->trailer(string $key, string $value, bool $ucwords = true);
参数
string $key
- 功能:
Http
头的Key
- 默认值:无
- 其它值:无
- 功能:
string $value
- 功能:
Http
头的value
- 默认值:无
- 其它值:无
- 功能:
string $ucwords
- 功能: 是否需要对
Key
进行Http
约定格式化【默认true
会自动格式化】 - 默认值:
true
- 其它值:无
- 功能: 是否需要对
返回值
- 设置失败,返回
false
- 设置成功,没有任何返回值
- 设置失败,返回
注意
- 重复设置相同
$key
的Http
头会覆盖,取最后一次。
- 重复设置相同
示例
$response->trailer('grpc-status', 0);
$response->trailer('grpc-message', '');
cookie()
?> 设置HTTP
响应的cookie
信息。此方法参数与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 = '');
注意
!> -
cookie
设置必须在end方法之前
-$samesite
参数从v4.4.6
版本开始支持
-Swoole
会自动会对$value
进行urlencode
编码,可使用rawCookie()
方法关闭对$value
的编码处理
-Swoole
允许设置多个相同$key
的COOKIE
rawCookie()
?> 设置HTTP
响应的cookie
信息
!> rawCookie()
的参数和上文的cookie()
一致,只不过不进行编码处理
status()
?> 发送Http
状态码。
Swoole\Http\Response->status(int $http_status_code, int $reason): bool;
参数
int $http_status_code
- 功能: 设置
HttpCode
- 默认值:
200
- 其它值:无
- 功能: 设置
int $reason
- 功能: 可设置任意
HttpCode
- 默认值:无
- 其它值:无
- 功能: 可设置任意
提示
- 如果只传入了第一个参数
$http_status_code
必须为合法的HttpCode
,如200
、502
、301
、404
等,否则会设置为200
状态码 - 如果设置了第二个参数
$reason
,$http_status_code
可以为任意的数值,包括未定义的HttpCode
,如499
- 必须在 $response->end() 之前执行
status
方法
- 如果只传入了第一个参数
gzip()
!> 此方法在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);
参数
int $level
- 功能:压缩等级,等级越高压缩后的尺寸越小,但
CPU
消耗更多。 - 默认值:1
- 其它值:
1-9
- 功能:压缩等级,等级越高压缩后的尺寸越小,但
!> 调用gzip
方法后,底层会自动添加Http
编码头,PHP代码中不应当再行设置相关Http
头;jpg/png/gif
格式的图片已经经过压缩,无需再次压缩
!> gzip
功能依赖zlib
库,在编译swoole时底层会检测系统是否存在zlib
,如果不存在,gzip
方法将不可用。可以使用yum
或apt-get
安装zlib
库:
sudo apt-get install libz-dev
redirect()
?> 发送Http
跳转。调用此方法会自动end
发送并结束响应。
Swoole\Http\Response->redirect(string $url, int $http_code = 302): void;
参数
string $url
- 功能:跳转的新地址,作为
Location
头进行发送 - 默认值:无
- 其它值:无
- 功能:跳转的新地址,作为
int $http_code
- 功能:状态码【默认为
302
临时跳转,传入301
表示永久跳转】 - 默认值:
302
- 其它值:无
- 功能:状态码【默认为
示例
$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();
write()
?> 启用Http Chunk
分段向浏览器发送相应内容。
?> 关于Http Chunk
可以参考Http
协议标准文档。
Swoole\Http\Response->write(string $data): bool;
参数
string $data
- 功能:要发送的数据内容【最大长度不得超过
2M
,受buffer_output_size配置项控制】 - 默认值:无
- 其它值:无
- 功能:要发送的数据内容【最大长度不得超过
提示
- 使用
write
分段发送数据后,end方法将不接受任何参数,调用end
只是会发送一个长度为0
的Chunk
表示数据传输完毕。
- 使用
sendfile()
?> 发送文件到浏览器。
Swoole\Http\Response->sendfile(string $filename, int $offset = 0, int $length = 0): bool;
参数
string $filename
- 功能:要发送的文件名称【文件不存在或没有访问权限
sendfile
会失败】 - 默认值:无
- 其它值:无
- 功能:要发送的文件名称【文件不存在或没有访问权限
int $offset
- 功能:上传文件的偏移量【可以指定从文件的中间部分开始传输数据。此特性可用于支持断点续传】
- 默认值:
0
- 其它值:无
int $length
- 功能:发送数据的尺寸
- 默认值:文件的尺寸
- 其它值:无
提示
- 底层无法推断要发送文件的MIME格式因此需要应用代码指定
Content-Type
- 调用
sendfile
前不得使用write
方法发送Http-Chunk
- 调用
sendfile
后底层会自动执行end
sendfile
不支持gzip
压缩
- 底层无法推断要发送文件的MIME格式因此需要应用代码指定
示例
$response->header('Content-Type', 'image/jpeg'); $response->sendfile(__DIR__.$request->server['request_uri']);
end()
?> 发送Http
响应体,并结束请求处理。
Swoole\Http\Response->end(string $html): bool;
参数
string $html
- 功能:要发送的内容
- 默认值:无
- 其它值:无
提示
detach()
?> 分离响应对象。使用此方法后,$response
对象销毁时不会自动end,与 Http\Response::create 和 Server::send 配合使用。
!> detach方法只能在 SWOOLE_PROCESS 模式下使用。
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();
create()
?> 构造新的Swoole\Http\Response
对象。
!> 使用此方法前请务必调用detach
方法将旧的$response
对象分离,否则可能会造成对同一个请求发送两次响应内容。
Swoole\Http\Response::create(int $fd): Swoole\Http\Response;
!> 调用成功返回一个新的Http\Response
对象,调用失败返回false
参数
int $fd
- 功能:参数为需要绑定的连接
$fd
【调用Http\Response
对象的end
与write
方法时会向此连接发送数据】 - 默认值:无
- 其它值:无
- 功能:参数为需要绑定的连接
示例
$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();
配置选项
upload_tmp_dir
?> 设置上传文件的临时目录。目录最大长度不得超过220
字节
$server->set(array(
'upload_tmp_dir' => '/data/uploadfiles/',
));
http_parse_post
?> 针对Request
对象的配置,设置POST消息解析开关,默认开启
- 设置为
true
时自动将Content-Type为x-www-form-urlencoded
的请求包体解析到POST
数组。 - 设置为
false
时将关闭POST
解析。
$server->set(array(
'http_parse_post' => false,
));
http_parse_cookie
?> 针对Request
对象的配置,关闭Cookie
解析,将在header
中保留未经处理的原始的Cookies
信息。默认开启
$server->set(array(
'http_parse_cookie' => false,
));
http_compression
?> 针对Response
对象的配置,启用压缩。默认为开启。
!> - http-chunk
不支持分段单独压缩, 若使用write方法, 将会强制关闭压缩。
-http_compression
在v4.1.0
或更高版本可用
$server->set(array(
'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
。
http_compression_level
?> 压缩级别,针对Response
对象的配置
!> $level
压缩等级,范围是1-9
,等级越高压缩后的尺寸越小,但CPU
消耗更多。默认为1
, 最高为9
document_root
?> 配置静态文件根目录,与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代码和静态文件进行隔离,静态文件存放到特定的目录
enable_static_handler
开启静态文件请求处理功能, 需配合document_root
使用 默认false
static_handler_locations
?> 设置静态处理器的路径。类型为数组,默认不启用。
!> Swoole >= v4.4.0
$server->set([
"static_handler_locations" => ['/static', '/app/images'],
]);
- 类似于
Nginx
的location
指令,可以指定一个或多个路径为静态路径。只有URL
在指定路径下才会启用静态文件处理器,否则会视为动态请求。 location
项必须以/开头- 支持多级路径,如
/app/images
- 启用
static_handler_locations
后,如果请求对应的文件不存在,将直接返回404错误
open_http2_protocol
?> 启用HTTP2
协议解析【默认值:false
】
注意
!> 需要编译时启用 --enable-http2 选项