這篇文章主要講解了“Swoole與HTTP的使用介紹”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“Swoole與HTTP的使用介紹”吧!
目前成都創(chuàng)新互聯(lián)已為上1000家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)站空間、網(wǎng)站運(yùn)營(yíng)、企業(yè)網(wǎng)站設(shè)計(jì)、盤山網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。
目標(biāo)
了解swoole的http_server的使用
了解swoole的tcp服務(wù)開(kāi)發(fā)
實(shí)際項(xiàng)目中問(wèn)題如粘包處理、代理熱更新、用戶驗(yàn)證等。
swoole與現(xiàn)有框架結(jié)合
推薦(免費(fèi)):swoole
風(fēng)格
偏基礎(chǔ)重代碼
環(huán)境
PHP版本:
Swoole版本:https://github.com/swoole/swoole-src
zphp開(kāi)發(fā)框架:https://github.com/shenzhe/zphp
HTTP Server
靜態(tài)文件處理
動(dòng)態(tài)請(qǐng)求與框架結(jié)合
# 查看SWOOLE版本 $ php -r 'echo SWOOLE_VERSION;' 4.3.1
基礎(chǔ)概念
HTTP報(bào)文
關(guān)于HTTP請(qǐng)求報(bào)文的組成結(jié)構(gòu)
HTTP請(qǐng)求報(bào)文結(jié)構(gòu)
POST /search HTTP/1.1 Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-silverlight, application/x-shockwave-flash, */* Referer: http://www.google.cn/ Accept-Language: zh-cn Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; TheWorld) Host: www.google.cn Connection: Keep-Alive Cookie: PREF=ID=80a06da87be9ae3c:U=f7167333e2c3b714:NW=1:TM=1261551909:LM=1261551917:S=ybYcq2wpfefs4V9g; NID=31=ojj8d-IygaEtSxLgaJmqSjVhCspkviJrB6omjamNrSm8lZhKy_yMfO2M4QMRKcH1g0iQv9u-2hfBW7bUFwVh7pGaRUb0RnHcJU37y- FxlRugatx63JLv7CWMD6UB_O_r hl=zh-CN&source=hp&q=domety
關(guān)于HTTP響應(yīng)報(bào)文的組成結(jié)構(gòu)
HTTP響應(yīng)報(bào)文結(jié)構(gòu)
HTTP/1.1 200 OK Date: Mon, 23 May 2005 22:38:34 GMT Content-Type: text/html; charset=UTF-8 Content-Encoding: UTF-8 Content-Length: 138 Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT Server: Apache/1.3.3.7 (Unix) (Red-Hat/Linux) ETag: "3f80f-1b6-3e1cb03b" Accept-Ranges: bytes Connection: close
創(chuàng)建HTTP服務(wù)器
Swoole在1.7.7版本后內(nèi)置HTTP服務(wù)器,可創(chuàng)建一個(gè)異步非阻塞多進(jìn)程的HTTP服務(wù)器。Swoole的HTTP服務(wù)器對(duì)HTTP協(xié)議支持的并不完整,建議僅作為應(yīng)用服務(wù)器,并在前端增加Nginx作為代理。
因?yàn)镾woole是在CLI命令行中執(zhí)行的,在傳統(tǒng)的NGINX+FastCGI模式下很多root
的shell
是無(wú)法執(zhí)行的,而使用Swoole服務(wù)器就能很好的控制rsync
、git
、svn
等。
使用Swoole的API,構(gòu)建HTTP服務(wù)器需要4個(gè)步驟
創(chuàng)建Server對(duì)象
設(shè)置運(yùn)行時(shí)參數(shù)
注冊(cè)事件回調(diào)函數(shù)
啟動(dòng)服務(wù)器
# 創(chuàng)建應(yīng)用 $ mkdir test && cd test # 創(chuàng)建并編輯服務(wù)器文件 $ vim server.php
set($configs); //注冊(cè)監(jiān)聽(tīng)客戶端HTTP請(qǐng)求回調(diào)事件 $server->on("request", function(swoole_http_request $request, swoole_http_response $response) use($server){ var_dump($request); var_dump($response); //獲取客戶端文件描述符 $fd = $request->fd; if(!empty($fd)){ //獲取連接信息 $clientinfo = $server->getClientInfo($fd); var_dump($clientinfo); //獲取收包時(shí)間 var_dump($clientinfo["last_time"]); } //響應(yīng)客戶端HTTP請(qǐng)求 $response->write("success");//向客戶端寫入響應(yīng)數(shù)據(jù) $response->end();//瀏覽器中輸出結(jié)果 }); //啟動(dòng)服務(wù)器 $server->start();
# 使用PHP-CLI運(yùn)行服務(wù)器腳本 $ php server.php # 使用CURL向HTTP服務(wù)器發(fā)送請(qǐng)求測(cè)試 $ curl 127.0.0.1:9501
使用注意
echo
、var_dump
、print_r
的內(nèi)容是在服務(wù)器中輸出的
瀏覽器中輸出需要使用$rp->end(string $contents)
,end()
方法只能調(diào)用一次。
如果需要多次先客戶端發(fā)送消息可使用$rp->write(string $content)
方法
完整的HTTP協(xié)議請(qǐng)求會(huì)被解析并封裝在swoole_http_request
對(duì)象中
所有的HTTP協(xié)議響應(yīng)會(huì)通過(guò)swoole_http_response
對(duì)象進(jìn)行封裝并發(fā)送
HTTP服務(wù)器的本質(zhì)
由于swoole_http_server
是基于swoole_server
的,所以swoole_server
下的方法在swoole_http_server
中都可以使用,只是swoole_http_server
只能被客戶端喚起。簡(jiǎn)單來(lái)說(shuō),swoole_http_server
是基于swoole_server
加上HTTP
協(xié)議,再加上request
和response
類庫(kù)去實(shí)現(xiàn)請(qǐng)求數(shù)據(jù)和獲取數(shù)據(jù)。與PHP-FPM不同的是,Web服務(wù)器收到請(qǐng)求后會(huì)傳遞給Swoole的HTTP
服務(wù)器,直接返回請(qǐng)求。
swoole_http_server
Swoole\HTTP\Server
繼承自Server,是一個(gè)HTTP服務(wù)器實(shí)現(xiàn),支持同步與有異步兩種模式。無(wú)論是同步模式還是異步模式,HTTP服務(wù)器都可以維持大量的TCP客戶端連接,同步與異步僅僅提現(xiàn)在對(duì)請(qǐng)求的處理方式。
同步模式
同步模式等同于Nginx
+PHP-FPM/Apache
,需要設(shè)置大量Worker工作進(jìn)程來(lái)完成并發(fā)請(qǐng)求處理,Worker工作進(jìn)程可以使用同步阻塞IO,編程方式與普通的PHP的Web程序完全一致。與PHP-FPM/Apache
不同的是,客戶端連接并不會(huì)獨(dú)占進(jìn)程,服務(wù)器依然可以應(yīng)對(duì)大量并發(fā)連接。
異步模式
異步模式下整個(gè)HTTP服務(wù)器是異步非阻塞的,服務(wù)器可以應(yīng)答大規(guī)模的并發(fā)連接和并發(fā)請(qǐng)求,編程方式需要完全使用異步API,如MySQL、redis、HTTP客戶端、file_get_contents
、sleep
等阻塞IO操作必須切換為異步方式,如異步Client、Event、Timer等API。
查看HTTP服務(wù)器實(shí)例對(duì)象
var_dump($server);
object(Swoole\Connection\Iterator)#2 (0) { ["host"]=>string(7) "0.0.0.0" ["port"]=>int(9501) ["type"]=>int(1) ["mode"]=>int(2) ["ports"]=> array(1) { [0]=> object(Swoole\Server\Port)#3 (16) { ["onConnect":"Swoole\Server\Port":private]=>NULL ["onReceive":"Swoole\Server\Port":private]=>NULL ["onClose":"Swoole\Server\Port":private]=>NULL ["onPacket":"Swoole\Server\Port":private]=>NULL ["onBufferFull":"Swoole\Server\Port":private]=>NULL ["onBufferEmpty":"Swoole\Server\Port":private]=>NULL ["onRequest":"Swoole\Server\Port":private]=>NULL ["onHandShake":"Swoole\Server\Port":private]=>NULL ["onOpen":"Swoole\Server\Port":private]=>NULL ["onMessage":"Swoole\Server\Port":private]=>NULL ["host"]=>string(7) "0.0.0.0" ["port"]=>int(9501) ["type"]=>int(1) ["sock"]=>int(4) ["setting"]=>NULL ["connections"]=>object(Swoole\Connection\Iterator)#4 (0) { } } } ["master_pid"]=>int(0) ["manager_pid"]=>int(0) ["worker_id"]=>int(-1) ["taskworker"]=>bool(false) ["worker_pid"]=>int(0) ["onRequest":"Swoole\Http\Server":private]=>NULL ["onHandshake":"Swoole\Http\Server":private]=>NULL }
配置選項(xiàng)
upload_tmp_dir
HTTP服務(wù)器支持大文件上傳,但由于Swoole底層的限制,文件內(nèi)容是存放在內(nèi)存中的,因此如果并發(fā)上傳大量文件可能會(huì)導(dǎo)致內(nèi)存占用量過(guò)大的問(wèn)題。
可以修改upload_tmp_dir
選項(xiàng)用于配置上傳文件的臨時(shí)目錄,需要注意是目錄文件夾的名稱最大長(zhǎng)度不得超過(guò)220個(gè)字節(jié)。
$configs = []; $configs["upload_tmp_dir"] = "/data/uploads/"; $server->set($configs);
POST解析http_parse_post
可通過(guò)修改http_parse_post
配置項(xiàng)用來(lái)設(shè)置表單POST提交后是否解析,若設(shè)置為true
則表示會(huì)自動(dòng)將Content-Type
內(nèi)容類型為x-www-urlencode
的請(qǐng)求包體解析到 POST 數(shù)組,若設(shè)置為false
則表示將會(huì)關(guān)閉 POST解析。
$configs = []; $configs["http_parse_post"] = true; $server->set($configs);
POST尺寸 package_max_length
默認(rèn)情況下,表單上傳或POST
提交2MB的數(shù)據(jù)的限制,可通過(guò)修改package_max_length
選項(xiàng)調(diào)整POST尺寸大小。
$configs = []; $configs["package_max_length"] = 2*1024; $server->set($configs);
解析Cookiehttp_parse_cookie
通過(guò)修改http_parse_cookie
配置項(xiàng)可以開(kāi)啟或關(guān)閉Cookie解析,關(guān)閉后將會(huì)在Header頭信息學(xué)中保留未經(jīng)處理的原始Cookies信息。
$configs = []; $configs["http_parse_cookie"] = true; $server->set($configs);
http_compression
http_compression
適用于Swoole4.1.0+版本,用于啟用或關(guān)閉對(duì)HTTP信息的壓縮,默認(rèn)為開(kāi)啟狀態(tài)。
由于http-chunk
不支持分段獨(dú)立壓縮,因此默認(rèn)已強(qiáng)制關(guān)閉了壓縮功能。
$configs = []; $configs["http_compression"] = false; $server->set($configs);
目前HTTP支持gzip
、br
(需google brotli
庫(kù)支持)、deflate
三種壓縮格式,Swoole底層會(huì)根據(jù)客戶端瀏覽器傳入的Accept-Encoding
頭信息自動(dòng)選擇壓縮方式。
http_compression_level
http_compression_level
選項(xiàng)用于配置壓縮的級(jí)別,壓縮級(jí)別越高壓縮后體積越小,同時(shí)也會(huì)越占用CPU。
$configs = []; $configs["http_compression_level"] = 1; $server->set($configs);
document_root
document_root
選項(xiàng)適用于Swoole1.9.17+版本,用于配置靜態(tài)文件的根目錄,該功能由于較為簡(jiǎn)易不推薦在公網(wǎng)環(huán)境下直接使用,常于enable_static_handler
選項(xiàng)配合使用。
如果設(shè)置document_root
和enable_static_handler = true
后,Swoole底層收到HTTP請(qǐng)求時(shí)會(huì)先判斷document_root
的路徑下是否存在某靜態(tài)文件,如果存在會(huì)直接發(fā)送內(nèi)容給客戶端,并不再調(diào)用onRequest
函數(shù)。
這里需要注意的時(shí),在使用靜態(tài)文件處理特性時(shí),應(yīng)當(dāng)將動(dòng)態(tài)PHP代碼于靜態(tài)文件進(jìn)行隔離,靜態(tài)文件應(yīng)存放到特定的目錄下。
$configs = []; $configs["document_root"] = "/app"; $server->set($configs);
enable_static_handler
enable_static_handler
選項(xiàng)用于開(kāi)啟或關(guān)閉靜態(tài)文件請(qǐng)求處理功能,常配合document_root
選項(xiàng)使用。
$configs = []; $configs["enable_static_handler"] = true; $server->set($configs);
static_handler_locations
static_handler_location
選項(xiàng)適用于Swoole4.4.0+版本,用于設(shè)置靜態(tài)處理器的路徑,類型為數(shù)組,默認(rèn)不啟用。
靜態(tài)處理器類似于Nginx的location
指令,可以指定一個(gè)或多個(gè)路徑為靜態(tài)路徑。只有URL在指定路徑下才會(huì)啟用靜態(tài)問(wèn)而建處理器,否則會(huì)視為動(dòng)態(tài)請(qǐng)求。location
選項(xiàng)必須以/
開(kāi)頭并支持多級(jí)路徑,如/app/images
。
當(dāng)啟用static_handler_locations
選項(xiàng)后,如果請(qǐng)求對(duì)應(yīng)的文件不存在,將直接會(huì)返回404錯(cuò)誤。
$configs = []; $configs["static_handler_locations"] = ["/static", "/public/assets"]; $server->set($configs);
由于swoole_http_server
對(duì)HTTP協(xié)議支持的并不完整,建議僅僅作為應(yīng)用服務(wù)器,并在前端增加Nginx作為反向代理。
操作前需要修改服務(wù)器的運(yùn)行參數(shù),設(shè)置enable_static_handle
為true
后,底層收到HTTP請(qǐng)求會(huì)像判斷document_root
路徑下是否存在目標(biāo)文件,若存在則會(huì)直接發(fā)送文件給客戶端,不再觸發(fā)onRequest
回調(diào)。
設(shè)置服務(wù)器運(yùn)行時(shí)環(huán)境
$ vim server.php
$configs = []; $configs["enable_static_handler"] = true; $configs["document_root"] = "/test"; $server->set($configs);
設(shè)置Nginx反向代理配置
例如:設(shè)置Nginx反向代理127.0.0.1:9501
$ vim /usr/local/nginx/conf/nginx.conf
http { include mime.types; default_type application/octet-stream; #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"'; #access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; upstream swoole{ server 127.0.0.1:9501; keepalive 4; } server { listen 80; server_name www.swoole.com; #charset koi8-r; #access_log logs/host.access.log main; location / { proxy_pass http://swoole; proxy_set_header Connection ""; proxy_http_version 1.1; root html; index index.html index.htm; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } }
Nginx+Swoole的組合中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; } } }
請(qǐng)求對(duì)象
swoole_http_request
請(qǐng)求對(duì)象保存了HTTP客戶端請(qǐng)求的相關(guān)信息,包括GET
、POST
、COOKIE
、Header
等,請(qǐng)求對(duì)象$request
銷毀時(shí)會(huì)自動(dòng)刪除上傳的臨時(shí)文件,不要使用&
符號(hào)引用$request
請(qǐng)求對(duì)象。
var_dump($request); object(Swoole\Http\Request)#6 (10) { ["fd"]=>int(1) ["streamId"]=>int(0) ["header"]=>array(3) { ["host"]=>string(14) "127.0.0.1:9501" ["user-agent"]=>string(11) "curl/7.52.1" ["accept"]=>string(3) "*/*" } ["server"]=>array(10) { ["request_method"]=>string(3) "GET" ["request_uri"]=>string(1) "/" ["path_info"]=>string(1) "/" ["request_time"]=>int(1561689532) ["request_time_float"]=>float(1561689533.0563) ["server_port"]=>int(9501) ["remote_port"]=>int(51188) ["remote_addr"]=>string(9) "127.0.0.1" ["master_time"]=>int(1561689532) ["server_protocol"]=>string(8) "HTTP/1.1" } ["request"]=>NULL ["cookie"]=>NULL ["get"]=>NULL ["files"]=>NULL ["post"]=>NULL ["tmpfiles"]=>NULL }
HTTP請(qǐng)求的頭部信息,類型為數(shù)組,所有的鍵名均為小寫。
$host = $request->header["host"]; $accept = $request->header["accept"];
Http\Request->$server
HTTP請(qǐng)求相關(guān)的服務(wù)器信息,相當(dāng)于PHP的$_SERVER
全局?jǐn)?shù)組,包含了HTTP請(qǐng)求的方法、URL路徑、客戶端IP等信息。服務(wù)器信息為關(guān)聯(lián)數(shù)組,數(shù)組中的鍵名全部小寫,并且與PHP的$_SERVER
數(shù)組保持一致。
$request_method = $request->server["request_method"]; $request_time = $request->server["request_time"]; $request_uri = $request->server["request_uri"];
請(qǐng)求路徑
當(dāng)Google的Chrome瀏覽器訪問(wèn)服務(wù)器是會(huì)產(chǎn)生兩次請(qǐng)求,這是因?yàn)镃hrome會(huì)自動(dòng)請(qǐng)求一次favicon.ico
文件,所以服務(wù)器會(huì)收到兩個(gè)HTTP請(qǐng)求,通過(guò)打印$request->server["request_uri"]
可以查看到請(qǐng)求URL路徑。如果需要屏蔽掉對(duì)favicon.ico
的請(qǐng)求,可采用以下方式。
$uri = $request->server["request_uri"]; if($uri == "/favicon.icon") { $respoonse->status(404); $response->end(); }
收包時(shí)間
request_time
請(qǐng)求時(shí)間是在Worker工作進(jìn)程中設(shè)置的,在SWOOLE_PROCESS
多進(jìn)程模式下存在dispatch
分發(fā)的過(guò)程,因此可能會(huì)與實(shí)際收包時(shí)間存在偏差,尤其當(dāng)請(qǐng)求量超過(guò)服務(wù)器處理能力時(shí),有可能滯后于實(shí)際收包時(shí)間。
可通過(guò)Server->getClientInfo()
方法獲取last_time
以獲取 準(zhǔn)確的收包時(shí)間。
//獲取客戶端文件描述符 $fd = $request->fd; if(!empty($fd)){ //獲取連接信息 $clientinfo = $server->getClientInfo($fd); var_dump($clientinfo); //獲取收包時(shí)間 var_dump($clientinfo["last_time"]); }
客戶端信息
Server->getClientInfo()
用于獲取連接的客戶端信息
bool|array Server->getClientInfo(int $fd, int $extraData, bool $ignoreError = false)
int $fd
表示客戶端連接文件描述符
int $extraData
表示擴(kuò)展信息是保留參數(shù)目前無(wú)任何效果
bool $ignoreError
表示是否忽略錯(cuò)誤,若設(shè)置為true
表示即使連接關(guān)閉也會(huì)返回連接信息。
如果傳入的$fd
客戶端連接文件描述符存在則返回一個(gè)數(shù)組,若不存在或已關(guān)閉則返回false
。
array(10) { ["server_port"]=>int(9501) ["server_fd"]=>int(4) ["socket_fd"]=>int(12) ["socket_type"]=>int(1) ["remote_port"]=>int(51194) ["remote_ip"]=>string(9) "127.0.0.1" ["reactor_id"]=>int(0) ["connect_time"]=>int(1561690606) ["last_time"]=>int(1561690606) ["close_errno"]=>int(0) }
Http\Request->$get
HTTP請(qǐng)求的GET
參數(shù),相當(dāng)于PHP中的$_GET
,格式為鍵值對(duì)的關(guān)聯(lián)數(shù)組。為防止HASH
攻擊,GET
參數(shù)最大不允許超過(guò)128個(gè)。
$get = $request->get;//獲取HTTP請(qǐng)求的所有GET參數(shù)
HTTP的GET請(qǐng)求只有一個(gè)HTTP Header頭,Swowole底層使用固定大小的內(nèi)存緩沖區(qū)為8K,而且不可修改。如果請(qǐng)求不是正確的HTTP請(qǐng)求,將會(huì)出現(xiàn)錯(cuò)誤,底層會(huì)拋出錯(cuò)誤。
WARN swReactorThead_onReceive_http_request: http header is too long.
Http\Request->$post
HTTP請(qǐng)求攜帶POST
參數(shù),格式為鍵值對(duì)的關(guān)聯(lián)數(shù)組,POST
與Header
加起來(lái)的尺寸不得超過(guò)package_max_length
的設(shè)置,否則會(huì)認(rèn)為是惡意請(qǐng)求,另外POST
參數(shù)的個(gè)數(shù)不得超過(guò)128個(gè)。
$post = $request->post;
由于POST文件上傳時(shí)最大尺寸收到package_max_length
配置項(xiàng)目的限制,默認(rèn)為2MB,可以調(diào)用swoole_server->set
傳入新值修改尺寸。
由于Swoole底層是全內(nèi)存的,因此如果設(shè)置過(guò)大可能會(huì)導(dǎo)致大量并發(fā)請(qǐng)求,將服務(wù)器資源耗盡。
設(shè)置計(jì)算方法:最大內(nèi)存占用 = 最大并發(fā)請(qǐng)求數(shù)量 * package_max_length
當(dāng)使用CURL發(fā)送POST請(qǐng)求時(shí)服務(wù)器端會(huì)超時(shí)
CURL在發(fā)送較大的POST請(qǐng)求時(shí)會(huì)首先發(fā)送一個(gè)100-continue
的請(qǐng)求,當(dāng)收到服務(wù)器的回應(yīng)才會(huì)發(fā)送實(shí)際的POST數(shù)據(jù)。然后swoole_http_server
并不支持100-continue
,因此會(huì)導(dǎo)致CURL請(qǐng)求超時(shí)。解決的辦法時(shí)關(guān)閉CURL的100-continue。
$ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_POST, 1);//設(shè)置為POST方式 curl_setopt($ch, CURLOPT_HTTPHEADER, ["Exception:"]); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
Http\Request->$cookie
HTTP請(qǐng)求攜帶的COOKIE
信息,格式為鍵值對(duì)的關(guān)聯(lián)數(shù)組。
Http\Request->$files
HTTP請(qǐng)求攜帶的文件上傳信息,類型為以form
表單名稱為key
鍵名的二維數(shù)組,與PHP原生的$_FILES
相同,最大文件尺寸不得超過(guò)package_max_length
中設(shè)置的值,不要使用Swoole\Http\Server
處理大文件上傳。
$files = $request->files; var_dump($files);
array(5) { [name] => facepalm.jpg [type] => image/jpeg [tmp_name] => /tmp/swoole.upfile.n3FmFr [error] => 0 [size] => 15476 }
name
表示瀏覽器上傳時(shí)傳入的文件名稱
type
表示瀏覽器上傳時(shí)的MIME類型
tmp_name
表示瀏覽器上傳的臨時(shí)文件,文件名默認(rèn)以/tmp/swoole.upfile
開(kāi)頭。
size
表示上傳文件的尺寸
Swoole1.9.10+版本支持is_uploaded_file
和move_uploaded_file
函數(shù)。當(dāng)HTTP請(qǐng)求對(duì)象$request
對(duì)象銷毀時(shí),會(huì)自動(dòng)刪除上傳的臨時(shí)文件。
Http\Request->rawContent()
rawContent
表示獲取原始的POST
包體,用于非application/x-www-form-urlencode
格式的HTTP的POST
請(qǐng)求。等同于原生PHP的fopen("php://input")
,有時(shí)服務(wù)器不需要解析HTTP的POST請(qǐng)求參數(shù)。
Swoole1.7.18+版本增加了http_parse_post
配置用于關(guān)閉或開(kāi)啟POST
數(shù)據(jù)解析。
string HTTP\Request->rawContent();
Http\Request->getData()
getData()
方法用于獲取完整的HTTP請(qǐng)求報(bào)文,包括 Http Header
和`HTTP Body消息體。
function swoole_http_request_getData() : string
getData
需要Swoole1.10.3或Swoole2.1.2或更高的版本。
響應(yīng)對(duì)象
swoole_http_response
響應(yīng)對(duì)象是進(jìn)程隔離的,不能跨越進(jìn)程或?qū)ο?。如果是?dāng)前進(jìn)程中,想使用fd
文件描述符保存response
響應(yīng)對(duì)象、存儲(chǔ)上下文,可使用PHP全局?jǐn)?shù)組變量來(lái)保存。
swoole_http_response
響應(yīng)對(duì)象,通過(guò)調(diào)用此對(duì)象的方法實(shí)現(xiàn)HTTP響應(yīng)的發(fā)送,當(dāng)響應(yīng)對(duì)象銷毀時(shí),如果沒(méi)有調(diào)用end
發(fā)送HTTP響應(yīng),底層會(huì)自動(dòng)執(zhí)行end
方法。不要使用&
符號(hào)引用$response
對(duì)象。
object(Swoole\Http\Response)#7 (4) { ["fd"]=>int(1) ["header"]=>NULL ["cookie"]=>NULL ["trailer"]=>NULL }
HTTP服務(wù)器Response響應(yīng)對(duì)象,通過(guò)調(diào)過(guò)此對(duì)象的方法,實(shí)現(xiàn)HTTP響應(yīng)發(fā)送。當(dāng)Response對(duì)象銷毀時(shí),如果未調(diào)用則直接調(diào)用end
方法,不要使用&
符號(hào)引用$response
對(duì)象。
Http\Response->header
function Http\Response->header( string $key, string $value, bool $ucworods = true )
header
方法用于設(shè)置HTTP響應(yīng)的Header頭信息,如果設(shè)置失敗返回false
,設(shè)置成功則無(wú)返回值。
string $key
表示HTTP頭的Key
string $value
表示HTTP頭的Value
bool $ucwords
表示是否需要對(duì)Key進(jìn)行HTTP約定格式化,默認(rèn)true
會(huì)自動(dòng)格式化。
$response->header("Content-Type", "image/jpeg", true);
跨域處理
$origin = $request->header['origin']; // Access-Control-Allow-Origin 不能使用 *,這樣修改是不支持php版本低于7.0的。 // $response->header('Access-Control-Allow-Origin', '*'); $response->header('Access-Control-Allow-Origin', $origin); $response->header('Access-Control-Allow-Methods', 'OPTIONS'); $response->header('Access-Control-Allow-Headers', 'x-requested-with,session_id,Content-Type,token,Origin'); $response->header('Access-Control-Max-Age', '86400'); $response->header('Access-Control-Allow-Credentials', 'true'); if ($request->server['request_method'] == 'OPTIONS') { $response->status(200); $response->end(); return; };
Http\Response->cookie
cookie
方法用來(lái)設(shè)置HTTP響應(yīng)的Cookie信息,方法參數(shù)與原生PHP的setcookie
函數(shù)完全一致。
function Http\Response->cookie( string $key, string $value = "", int $expire = 0, string $path = "/", string $domain = "", bool $secure = false, bool $httponly = false )
Cookie設(shè)置必須在end
方法之前方才生效,Swoole底層自動(dòng)會(huì)對(duì)$value
進(jìn)行urlencode
編碼處理,同時(shí)允許設(shè)置多個(gè)相同的$key
的Cookie。
Http\Response->status
swoole_http_response->status( int $http_status_code )
status
方法用于發(fā)送HTTP狀態(tài)碼,$http_status_code
必須是合法的HTTP狀態(tài)碼,如2xx、3xx、4xx、5xx等,若不是在會(huì)報(bào)錯(cuò),另外status
方法也必須在$response->end()
之前執(zhí)行方才生效。
string $url
表示跳轉(zhuǎn)的新地址會(huì)作為HTTP Header頭中的Location
選項(xiàng)進(jìn)行發(fā)送
int $http_code
表示狀態(tài)碼,默認(rèn)為302臨時(shí)跳轉(zhuǎn),傳入301表示永久跳轉(zhuǎn)。
Http\Response->redirect
redirect
方法適用于Swoole2.2.0+版本,用于發(fā)送HTTP跳轉(zhuǎn),調(diào)用后會(huì)自動(dòng)執(zhí)行end
方法并發(fā)送結(jié)束響應(yīng)。
function Http\Response->redirect( string $url, int $http_code = 302 )
例如
$server = new swoole_http_server("0.0.0.0", 9501, SWOOLE_BASE); $server->on("request", function(swoole_http_request $request, swoole_http_response $response){ $url = "http://www.baidu.com"; $response->redirect($url, 301); }); $server->start();
Http\Response->write
write
方法用于啟用HTTP的chunk
分段以向?yàn)g覽器發(fā)送相應(yīng)的內(nèi)容,使用write
分段發(fā)送數(shù)據(jù)后end
方法將不再接收任何參數(shù),調(diào)用end
方法后會(huì)發(fā)送一個(gè)長(zhǎng)度為0的分段chunk
表示數(shù)據(jù)傳輸完畢。
bool Http\Response->write(string $data)
參數(shù)$data
表示要發(fā)送的數(shù)據(jù)內(nèi)容,最大長(zhǎng)度不得超過(guò)2MB,受buffer_output_size
配置項(xiàng)控制。
Http\Response->sendfile
sendfile
用于發(fā)送文件到瀏覽器
function Http\Response->sendfile( string $filename, int $offset = 0, int $length = 0 )
string $filename
表示要發(fā)送的文件名稱,文件不存在或沒(méi)有訪問(wèn)權(quán)限則會(huì)發(fā)送失敗。
int $offset
表示上傳文件的偏移量,可以指定從文件在中間部分開(kāi)始傳輸數(shù)據(jù),用于斷點(diǎn)續(xù)傳,適用于Swoole1.9.11+。
int $length
表示發(fā)送數(shù)據(jù)的尺寸,默認(rèn)為整個(gè)文件的尺寸,適用于Swoole1.9.11+。
$response->header("Content-Type", "image/jpeg"); $filepath = $request->server["request_uri"]; $filename = __DIR__.$filepath; $response->sendfile($filename);
由于Swoole底層無(wú)法推斷要發(fā)送文件的媒體類型MIME
格式,因此需要應(yīng)用程序指定Content-Type
。調(diào)用sendfile
前不得使用write
方法發(fā)送HTTP數(shù)據(jù)段Chunk
,調(diào)用sendfile
后Swoole底層會(huì)自動(dòng)執(zhí)行end
方法,另外sendfile
不支持gzip
壓縮。
Http\Response->end
end
方法用于發(fā)送HTTP響應(yīng)體,并結(jié)束請(qǐng)求處理。
function Http\Response->end(string $html);
end
方法只能調(diào)用一次,如果需要分多次向客戶端發(fā)送數(shù)據(jù)下需使用write
方法,send
操作后將會(huì)向客戶端瀏覽器發(fā)送HTML內(nèi)容。如果客戶端開(kāi)啟了KeepAlive
連接會(huì)保持,服務(wù)器會(huì)等待下一次請(qǐng)求。如果沒(méi)有開(kāi)啟KeepAlive
服務(wù)器將會(huì)切斷連接。
Http\Response->detach
detach
表示分離響應(yīng)對(duì)應(yīng),調(diào)用后$response
對(duì)象銷毀時(shí)將不會(huì)自動(dòng)執(zhí)行end
方法,一般detach
會(huì)與Http\Response::create
以及Server::send
配合使用,適用于Swoole2.2.0+版本。
function Http\Response->detach():bool
detach
方法操作后,若客戶端已經(jīng)完成響應(yīng)則會(huì)返回true
,否則返回false
。
detach
應(yīng)用于跨進(jìn)程響應(yīng)
在某些情況下需要在Task
任務(wù)進(jìn)程中對(duì)客戶端發(fā)出響應(yīng),此時(shí)可以利用detach
方法使$response
對(duì)象獨(dú)立,如此一來(lái)在Task
任務(wù)進(jìn)程中就可以重新構(gòu)建$response
對(duì)象以發(fā)起HTTP請(qǐng)求響應(yīng)。
set($configs); //注冊(cè)客戶端請(qǐng)求處理回調(diào)函數(shù) $server->on("request", function(swoole_http_request $request, swoole_http_response $response) use($server){ //分離響應(yīng)對(duì)象 $response->detach(); //在Task任務(wù)進(jìn)程中對(duì)客戶端發(fā)出響應(yīng) $fd = strval($response->fd); $server->task($fd); }); //注冊(cè)異步任務(wù)處理回調(diào)函數(shù) $server->on("task", function(swoole_http_server $server, $worker_id, $data){ //創(chuàng)建響應(yīng)對(duì)象 $response = swoole_http_response::create($data); //向客戶端發(fā)送響應(yīng) $html = "in task"; $response->end($html); }); //注冊(cè)Task異步任務(wù)執(zhí)行完畢回調(diào)函數(shù) $server->on("finish", function(){ echo "[finish] task".PHP_EOL; }); //啟動(dòng)服務(wù)器 $server->start();
detach
方法應(yīng)用于發(fā)送任意內(nèi)容
在某些特殊場(chǎng)景下,需要對(duì)客戶端發(fā)送特殊的響應(yīng)內(nèi)容,Http\Response
對(duì)象自帶的end
方法無(wú)法滿足需求,可以使用detach
方法分離響應(yīng)對(duì)象,然后自行組包并使用Server::send
方法發(fā)送數(shù)據(jù)。
set($configs); //注冊(cè)監(jiān)聽(tīng)客戶端HTTP請(qǐng)求回調(diào)事件 $server->on("request", function(swoole_http_request $request, swoole_http_response $response) use($server){ //分離響應(yīng)對(duì)象 $response->detach(); //自行組包并使用Server::send方法發(fā)送數(shù)據(jù) $fd = $response->fd; $message = "HTTP/1.1 200 OK\r\n"; $message .= "Server: server\r\n"; $message .= "\r\n"; $message .= "Hello World\n"; $server->send($fd, $message); }); //啟動(dòng)服務(wù)器 $server->start();
Http\Response::create
create
靜態(tài)方法用于構(gòu)造新的Http\Response
響應(yīng)對(duì)象,使用前必須調(diào)用detach
方法將舊有$response
對(duì)象分離,否則 可能會(huì)造成同一個(gè)請(qǐng)求發(fā)送兩次響應(yīng)內(nèi)容。
function Http\Response::createE(int $fd) : Http\Response
create
靜態(tài)方法的參數(shù)$fd
表示需要綁定連接的文件描述符,調(diào)用Http\Response
對(duì)象的end
方法和write
方法時(shí)會(huì)向此連接發(fā)送數(shù)據(jù)。如果調(diào)用成功則返回一個(gè)新的Http\Response
對(duì)象,否則失敗返回false
,適用于Swoole2.2.0+版本。
注冊(cè)事件回調(diào)函數(shù)
Http\Server
注冊(cè)事件回調(diào)函數(shù)于Http\Server->on
相同,不同之處在于HTTP\Server->on
不接受onConnect
和onReceive
回調(diào)設(shè)置,Http\Server->on
會(huì)額外接受一種新的事務(wù)類型onRequest
。
onRequest 事件
onRequest
事件適用于Swoole1.7.7+版本,當(dāng)服務(wù)器收到一個(gè)完整的HTTP請(qǐng)求后會(huì)調(diào)用onRequest
函數(shù)。
$server->on("request", function(swoole_http_request $request, swoole_http_response $response) use($server){ $html = "success"; $response->end($html); });
onRequest
回調(diào)函數(shù)共有兩個(gè)參數(shù)
swoole_http_requst $request
HTTP請(qǐng)求信息對(duì)象,包含了Header/GET/POST/Cookie等信息。
swoole_http_response $response
HTTP響應(yīng)信息對(duì)象,支持Cookie/Header/Status等HTTP操作。
在onRequest
回調(diào)函數(shù)返回時(shí)會(huì)銷毀$request
和$response
對(duì)象,如果未執(zhí)行$response->end()
操作,Swoole底層會(huì)自動(dòng)執(zhí)行一次$response->end("")
。
$request
和$response
對(duì)象在傳遞給其它函數(shù)時(shí),是不需要添加&
取地址的引用符號(hào)的,傳遞后引用計(jì)數(shù)會(huì)增加,當(dāng)onRequest
退出時(shí)并不會(huì)被銷毀。
案例
$ vim http_server.php
on("request", function(swoole_http_request $rq, swoole_http_response $rp){ //處理動(dòng)態(tài)請(qǐng)求 $path_info = $rq->server["path_info"]; $file = __DIR__.$path_info; echo "\nfile:{$file}"; if(is_file($file) && file_exists($file)){ $ext = pathinfo($path_info, PATHINFO_EXTENSION); echo "\next:{$ext}"; if($ext == "php"){ ob_start(); include($file); $contents = ob_get_contents(); ob_end_clean(); }else{ $contents = file_get_contents($file); } echo "\ncontents:{$contents}"; $rp->end($contents); }else{ $rp->status(404); $rp->end("404 not found"); } }); $svr->start();
# 創(chuàng)建靜態(tài)文件 $ vim index.html index.html # 測(cè)試靜態(tài)文件 $ curl 127.0.0.1:9501/index.html # 觀察http_server輸出 file:/home/jc/projects/swoole/chat/index.html ext:html contents:index.html # 測(cè)試動(dòng)態(tài)文件 $ vim index.php獲取動(dòng)態(tài)請(qǐng)求的參數(shù)
$ vim http_server.phpon("request", function(swoole_http_request $rq, swoole_http_response $rp){ //獲取請(qǐng)求參數(shù) $params = $rq->get; echo "\nparams:".json_encode($params); //處理動(dòng)態(tài)請(qǐng)求 $path_info = $rq->server["path_info"]; $file = __DIR__.$path_info; echo "\nfile:{$file}"; if(is_file($file) && file_exists($file)){ $ext = pathinfo($path_info, PATHINFO_EXTENSION); echo "\next:{$ext}"; if($ext == "php"){ ob_start(); include($file); $contents = ob_get_contents(); ob_end_clean(); }else{ $contents = file_get_contents($file); } echo "\ncontents:{$contents}"; $rp->end($contents); }else{ $rp->status(404); $rp->end("404 not found"); } }); $svr->start();測(cè)試帶參數(shù)的請(qǐng)求
$ curl 127.0.0.1:9501?k=v觀察請(qǐng)求參數(shù)的輸出
params:{"k":"v"} file:/home/jc/projects/swoole/chat/index.html ext:html contents:index.html靜態(tài)文件處理
$ vim mimes.php"image/jpeg", "jpeg"=>"image/jpeg", "bmp"=>"image/bmp", "ico"=>"image/x-icon", "gif"=>"image/gif", "png"=>"image/png", "css"=>"text/css", "html"=>"text/html", "xml"=>"text/xml", "bin"=>"application/octet-stream", "js"=>"application/javascript", "tar"=>"application/x-tar", "ppt"=>"application/vnd.ms-powerpoint", "pdf"=>"application/pdf", "swf"=>"application/x-shockwave-flash", "zip"=>"application/x-zip-compressed" ];$ vim http_server.phpset($cfg); //處理請(qǐng)求 $srv->on("request", function(swoole_http_request $rq, swoole_http_response $rp) use($srv){ //獲取請(qǐng)求文件信息與文件后綴 $path_info = $rq->server["path_info"]; $ext = pathinfo($path_info, PATHINFO_EXTENSION); //文件是否存在 $file = __DIR__.$path_info; if(!is_file($file) || !file_exists($file)){ $rp->status(404); $rp->end("404 NOT FOUND"); } //處理靜態(tài)請(qǐng)求 if($ext != "php"){ //設(shè)置響應(yīng)頭信息的內(nèi)容內(nèi)容 $mimes = include("mimes.php"); $rp->header("Content-Type", $mimes[$ext]); //獲取靜態(tài)文件內(nèi)容 $contents = file_get_contents($file); //返回內(nèi)容 $rp->end($contents); } }); //啟動(dòng)服務(wù) $srv->start();發(fā)送請(qǐng)求,瀏覽器訪問(wèn)
127.0.0.1:9501/test.jpeg
,查看圖片。面向?qū)ο?/strong>
$ vim http_server.phpset($options); } $srv->on("request", function(swoole_http_request $rq, swoole_http_response $rp) use($srv){ $rp->end("test"); $srv->close($rq->fd); }); $srv->start(); } } HttpServer::run("127.0.0.1", 9501, ["worker_num"=>2, "daemonize"=>0]);壓力測(cè)試
使用Apache Bench工具進(jìn)行壓力測(cè)試可以發(fā)現(xiàn),
swoole_http_server
遠(yuǎn)超過(guò)PHP-FPM、Golang自帶的HTTP服務(wù)器、Node.js自帶的HTTP服務(wù)器,性能接近Nginx的靜態(tài)文件處理。Swoole的http server與PHP-FPM的性能對(duì)比
安裝Apache的壓測(cè)工作ab
$ sudo apt install apache2-util使用100個(gè)客戶端跑1000次,平均每個(gè)客戶端10個(gè)請(qǐng)求。
$ ab -c 100 -n 1000 127.0.0.1:9501/index.php Concurrency Level: 100 Time taken for tests: 0.480 seconds Complete requests: 1000 Failed requests: 0 Total transferred: 156000 bytes HTML transferred: 9000 bytes Requests per second: 2084.98 [#/sec] (mean) Time per request: 47.962 [ms] (mean) Time per request: 0.480 [ms] (mean, across all concurrent requests) Transfer rate: 317.63 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 1 3.0 0 12 Processing: 4 44 10.0 45 57 Waiting: 4 44 10.1 45 57 Total: 16 45 7.8 45 57 Percentage of the requests served within a certain time (ms) 50% 45 66% 49 75% 51 80% 52 90% 54 95% 55 98% 55 99% 56 100% 57 (longest request)觀察可以發(fā)現(xiàn)QPS可以達(dá)到
Requests per second: 2084.98 [#/sec] (mean)
。HTTP SERVER 配置選項(xiàng)
swoole_server::set()
用于設(shè)置swoole_server
運(yùn)行時(shí)的各項(xiàng)參數(shù)化。$cfg = []; // 處理請(qǐng)求的進(jìn)程數(shù)量 $cfg["worker_num"] = 4; // 守護(hù)進(jìn)程化 $cfg["daemonize"] = 1; // 設(shè)置工作進(jìn)程的最大任務(wù)數(shù)量 $cfg["max_request"] = 0; $cfg["backlog"] = 128; $cfg["max_request"] = 50; $cfg["dispatch_mode"] = 1; $srv->set($cfg);配置HTTP SERVER參數(shù)后測(cè)試并發(fā)
$ vim http_server.phpset($cfg); $srv->on("request", function(swoole_http_request $rq, swoole_http_response $rp){ //獲取請(qǐng)求參數(shù) $params = $rq->get; echo "\nparams:".json_encode($params); //處理動(dòng)態(tài)請(qǐng)求 $path_info = $rq->server["path_info"]; $file = __DIR__.$path_info; echo "\nfile:{$file}"; if(is_file($file) && file_exists($file)){ $ext = pathinfo($path_info, PATHINFO_EXTENSION); echo "\next:{$ext}"; if($ext == "php"){ ob_start(); include($file); $contents = ob_get_contents(); ob_end_clean(); }else{ $contents = file_get_contents($file); } echo "\ncontents:{$contents}"; $rp->end($contents); }else{ $rp->status(404); $rp->end("404 not found"); } }); //啟動(dòng)服務(wù) $srv->start();查看進(jìn)程
$ ps -ef|grep http_server.php root 16224 1207 0 22:41 ? 00:00:00 php http_server.php root 16225 16224 0 22:41 ? 00:00:00 php http_server.php root 16227 16225 0 22:41 ? 00:00:00 php http_server.php root 16228 16225 0 22:41 ? 00:00:00 php http_server.php root 16229 16225 0 22:41 ? 00:00:00 php http_server.php root 16230 16225 0 22:41 ? 00:00:00 php http_server.php root 16233 2456 0 22:42 pts/0 00:00:00 grep --color=auto http_server.php查看后臺(tái)守護(hù)進(jìn)程
$ ps axuf|grep http_server.php root 16622 0.0
標(biāo)題名稱:Swoole與HTTP的使用介紹
鏈接分享:http://weahome.cn/article/ijochj.html