# http client
Swoole-1.8.0版本增加了對異步Http/WebSocket客戶端的支持。底層是用純C編寫,擁有超高的性能。
[TOC=2,3]
**啟用Http客戶端**
* 1.8.6版本之前,需要在編譯swoole時增加--enable-async-httpclient來開啟此功能。
* swoole_http_client不依賴任何第三方庫
* 支持Http-Chunk、Keep-Alive、form-data
* Http協議版本為HTTP/1.1
* gzip壓縮格式支持需要依賴zlib庫
## **構造方法**
~~~
function swoole_http_client->__construct(string $ip, int port, bool $ssl = false);
~~~
* $ip 目標服務器的IP地址,可使用swoole_async_dns_lookup查詢域名對應的IP地址
* $port 目標服務器的端口,一般http為80,https為443
* $ssl 是否啟用SSL/TLS隧道加密,如果目標服務器是https必須設置$ssl參數為true
**對象屬性**
* $body 請求響應后服務器端返回的內容
* $statusCode 服務器端返回的Http狀態碼,如404、200、500等
## **swoole_http_client->set**
設置客戶端參數,此方法與Swoole\Client->set接收的參數完全一致,可參考 Swoole\Client->set 方法的文檔。
除了設置TCPSocket的參數之外,Swoole\Http\Client 額外增加了一些選項,來控制Http和WebSocket客戶端。
**超時控制**
設置timeout選項,啟用Http請求超時檢測。單位為秒,最小粒度支持毫秒。
~~~
$http->set(['timeout' => 3.0]);
~~~
* 連接超時或被服務器關閉連接,statusCode將設置為-1
* 在約定的時間內服務器未返回響應,請求超時,statusCode將設置為-2
* 請求超時后底層會自動切斷連接
* 設置為-1表示永不超時,底層將不會添加超時檢測的定時器
>僅在1.9.14或更高版本可用
**keep_alive**
設置keep_alive選項,啟用或關閉Http長連接。
~~~
$http->set(['keep_alive' => false]);
~~~
**websocket_mask**
WebSocket客戶端啟用或關閉掩碼。默認為關閉。啟用后會對WebSocket客戶端發送的數據使用掩碼進行數據轉換。
~~~
$http->set(['websocket_mask' => true]);
~~~
## **swoole_http_client->setMethod**
設置Http請求方法
~~~
function swoole_http_client->setMethod(string $method);
$client->setMethod("PUT");
~~~
* $method 必須為符合Http標準的方法名稱,如果$method設置錯誤可能會被Http服務器拒絕請求
* setMethod僅在當前請求有效,發送請求后會理解清除method設置
## **swoole_http_client->setHeaders**
設置Http請求頭
~~~
function swoole_http_client->setHeaders(array $headers);
~~~
* $headers必須為鍵值對應的數組,底層會自動映射為$key: $value格式的Http標準頭格式
* setHeaders設置的Http頭在swoole_http_client對象存活期間的每次請求永久有效
* 重新調用setHeaders會覆蓋上一次的設置
## **swoole_http_client->setCookies**
設置Cookie
~~~
function swoole_http_client->setCookies(array $cookies);
~~~
* $cookies 設置COOKIE,必須為鍵值對應數組
* 設置COOKIE后在客戶端對象存活期間會持續保存
* 服務器端主動設置的COOKIE會合并到cookies數組中,可讀取$client->cookies屬性獲得當前Http客戶端的COOKIE信息
## **swoole_http_client->setData**
設置Http請求的包體
~~~
function swoole_http_client->setData(string $data);
~~~
* $data 為字符串格式
* 設置$data后并且未設置$method,底層會自動設置為POST
* 未設置Http請求包體并且未設置$method,底層會自動設置為GET
## **swoole_http_client->addFile**
添加POST文件。
~~~
function swoole_http_client->addFile(string $path, string $name, string $filename = null, string $mimeType = null, int $offset = 0, int $length)
~~~
* $path 文件的路徑,必選參數,不能為空文件或者不存在的文件
* $name 表單的名稱,必選參數,FILES參數中的key
* $filename 文件名稱,可選參數,默認為basename($path)
* $mimeType 文件的MIME格式,可選參數,底層會根據文件的擴展名自動推斷
* $offset 上傳文件的偏移量,可以指定從文件的中間部分開始傳輸數據。此特性可用于支持斷點續傳。
* $length 發送數據的尺寸,默認為整個文件的尺寸
使用addFile會自動將POST的Content-Type將變更為form-data。addFile底層基于sendfile,可支持異步發送超大文件。
>addFile在1.8.9或更高版本可用
>$offset, $length 參數在1.9.11或更高版本可用
**使用示例**
```
<?php
$cli = new swoole_http_client('127.0.0.1', 80);
//post request
$cli->setHeaders(['User-Agent' => "swoole"]);
$cli->addFile(__DIR__.'/post.data', 'post');
$cli->addFile(dirname(__DIR__).'/test.jpg', 'debug');
$cli->post('/dump2.php', array("xxx" => 'abc', 'x2' => 'rango'), function ($cli) {
echo $cli->body;
});
```
## **swoole_http_client->get**
發起GET請求,函數原型:
~~~
function swoole_http_client->get(string $path, callable $callback);
~~~
* $path 設置URL路徑,如/index.html,注意這里不能傳入http://domain
* $callback 調用成功或失敗后回調此函數
* 默認使用GET方法,可使用setMethod設置新的請求方法
* Http響應內容會在內存中進行數據拼接。因此如果響應體很大可能會占用大量內存
**使用實例**
~~~
$cli = new swoole_http_client('127.0.0.1', 80);
$cli->setHeaders([
'Host' => "localhost",
"User-Agent" => 'Chrome/49.0.2587.3',
'Accept' => 'text/html,application/xhtml+xml,application/xml',
'Accept-Encoding' => 'gzip',
]);
$cli->get('/index.php', function ($cli) {
echo "Length: " . strlen($cli->body) . "\n";
echo $cli->body;
});
~~~
## **swoole_http_client->post**
發起POST請求,函數原型:
~~~
function swoole_http_client->post(string $path, mixed $data, callable $callback);
~~~
* $path 設置URL路徑,如/index.html,注意這里不能傳入http://domain
* $data 請求的包體數據,如果$data為數組底層自動會打包為x-www-form-urlencoded格式的POST內容,并設置Content-Type為application/x-www-form-urlencoded
* $callback 調用成功或失敗后回調此函數
* 默認使用POST方法,可使用setMethod設置新的方法
**使用實例**
```
$cli = new swoole_http_client('127.0.0.1', 80);
$cli->post('/post.php', array("a" => '1234', 'b' => '456'), function ($cli) {
echo "Length: " . strlen($cli->body) . "\n";
echo $cli->body;
});
```
## **swoole_http_client->execute**
更底層的Http請求方法,需要代碼中調用setMethod和setData等接口設置請求的方法和數據。
~~~
function swoole_http_client->execute(string $path, callable $callback);
~~~
## **swoole_http_client->download**
通過Http下載文件。download與get方法的不同是download收到數據后會寫入到磁盤,而不是在內存中對Http Body進行拼接。因此download僅使用小量內存,就可以完成超大文件的下載。 函數原型:
~~~
function swoole_http_client->download(string $path, string $filename, callable $callback, int $offset = 0);
~~~
* $path URL路徑
* $filename 指定下載內容寫入的文件路徑,會自動寫入到downloadFile屬性
* $callback 下載成功后的回調函數
* $offset 指定寫入文件的偏移量,此選項可用于支持斷點續傳,可配合Http頭Range:bytes=$offset-實現
* $offset為0時若文件已存在,底層會自動清空此文件
* 執行成功返回true
* 打開文件失敗或feek失敗返回false
**使用示例**
```
$cli = new swoole_http_client('127.0.0.1', 80);
$cli->setHeaders([
'Host' => "localhost",
"User-Agent" => 'Chrome/49.0.2587.3',
'Accept' => '*',
'Accept-Encoding' => 'gzip',
]);
$cli->download('/video.avi', __DIR__.'/video.avi', function ($cli) {
var_dump($cli->downloadFile);
});
```
**斷點續傳**
```
$cli = new swoole_http_client('127.0.0.1', 80);
$file = __DIR__.'/video.avi';
$offset = filesize($file);
$cli->setHeaders([
'Host' => "localhost",
"User-Agent" => 'Chrome/49.0.2587.3',
'Accept' => '*',
'Accept-Encoding' => 'gzip',
'Range' => "bytes=$offset-",
]);
$cli->download('/video.avi', $file, function ($cli) {
var_dump($cli->downloadFile);
}, $offset);
```
## **swoole_http_client->close**
關閉連接,函數原型為:
~~~
function swoole_http_client->close() : bool
~~~
* 操作成功返回 true
>swoole_http_client與普通的swoole_client不同,close后如果再次請求get、post等方法時,底層會重新連接服務器
**異步http客戶端**
```php
<?php
class Http
{
public $parse_scheme;
public $parse_host;
public $parse_port;
public $parse_path;
public $parse_query;
public $real_ip;
public $client;
public $request_headers = [];
public $request_cookies = [];
public $request_data = [];
public $request_method = '';
public $onResponse = null;
public $onError = null;
public $ssl = false;
public function __construct($url,$method='get',$headers=[],$cookies=[])
{
$this->parse_url_to_array($url);
$available_methods = ['post','get'];
if(!in_array($method,$available_methods)){
throw new \Exception('request method is inavailable');
}
$this->request_headers = $headers;
$this->request_cookies = $cookies;
$this->request_method = $method;
$this->onError = function(){};
$this->onResponse = function(){};
}
public function parse_url_to_array($url)
{
$parsed_arr = parse_url($url);
$this->parse_scheme = isset($parsed_arr['scheme']) ? $parsed_arr['scheme'] : 'http';
$this->parse_host = isset($parsed_arr['host']) ? $parsed_arr['host'] : '127.0.0.1';
$this->parse_port = isset($parsed_arr['port']) ? $parsed_arr['port'] : $this->parse_scheme == 'https'?'443':'80';
$this->parse_path = isset($parsed_arr['path']) ? $parsed_arr['path'] : '/';
$this->parse_query = isset($parsed_arr['query']) ? $parsed_arr['query'] : '';
}
public function request($data=[])
{
$this->request_data = $data;
swoole_async_dns_lookup($this->parse_host, function($host, $ip){
if($ip == ''){
call_user_func_array($this->onError,[$host]);
return;
}
$this->real_ip = $ip;
if($this->parse_scheme === 'https'){
$this->ssl = true;
};
$this->client = new \Swoole\Http\Client($this->real_ip, $this->parse_port,$this->ssl);
$this->client->setHeaders($this->request_headers);
$this->client->setCookies($this->request_cookies);
$request_method = $this->request_method;
if($request_method == 'post'){
$this->client->post($this->parse_path.'?'.$this->parse_query,$this->request_data,$this->onResponse);
}else{
$this->client->get($this->parse_path.'?'.$this->parse_query,$this->onResponse);
}
});
}
}
$url = 'http://www.workerman.net';
$request_method = 'get';
$data = ['uid'=>1];
$http = new Http($url, $request_method);
$http->onResponse = function ($cli) {
var_dump($cli->body);
};
$http->request($data);
```
- swoole簡介
- swoole功能概述
- 序章
- 開發必讀
- 1 環境搭建
- 1.1 環境搭建
- 1.2 搭建Echo服務器
- 2 初識Swoole
- 2.1 Worker進程
- 2.2 TaskWorker進程
- 2.3 Timer定時器
- 2.4 Process進程
- 2.5 Table內存表
- 2.6 多端口監聽
- 2.7 sendfile文件支持
- 2.8 SSL支持
- 2.9 熱重啟
- 2.10 http_server
- 附錄*server配置
- 附錄*server函數
- 附錄*server屬性
- 附錄*server回調函數
- 附錄*server高級特性
- 心跳檢測
- 3 Swoole協議
- 3.1 EOF協議
- 3.2 固定包頭協議
- 3.3 Http協議
- 3.4 WebSocket協議
- 3.5 MTQQ協議
- 內置http_server
- 內置websocket_server
- Swoole\Redis\Server
- 4 Swoole異步IO
- 4.1 AsyncIO
- 異步文件系統IO
- swoole_async_readfile
- swoole_async_writefile
- swoole_async_read
- swoole_async_write
- 5 swoole異步客戶端
- ws_client
- http_client
- mysql_client
- redis_client
- tcp_client
- http2_client
- 6 swoole協程
- Swoole\Coroutine\Http\Client
- Swoole\Coroutine\MySQL
- Swoole\Coroutine\Redis
- Coroutine\PostgreSQL
- Swoole\Coroutine\Client
- Swoole\Coroutine\Socket
- Swoole\Coroutine\Channel
- Coroutine
- Swoole\Coroutine::create
- Swoole\Coroutine::resume
- Swoole\Coroutine::suspend
- Swoole\Coroutine::sleep
- Coroutine::getaddrinfo
- Coroutine::gethostbyname
- swoole_async_dns_lookup_coro
- Swoole\Coroutine::getuid
- getDefer
- setDefer
- recv
- Coroutine::stats
- Coroutine::fread
- Coroutine::fget
- Coroutine::fwrite
- Coroutine::readFIle
- Coroutine::writeFIle
- Coroutine::exec
- 7 swoole_process
- process::construct
- process::start
- process::name
- process::signal
- process::setaffinity
- process::exit
- process::kill
- process::daemon
- process->exec
- process::wait
- process::alarm
- 8 swoole定時器
- swoole_timer_tick
- swoole_timer_after
- swoole_timer_clear
- 9 swoole_event
- swoole_event_add
- swoole_event_set
- swoole_event_del
- swoole_event_wait
- swoole_event_defer
- swoole_event_write
- swoole_event_exit
- swoole提供的function
- 常見問題
- 客戶端鏈接失敗原因
- 如何設置進程數
- 如何實現異步任務
- 如何選擇swoole三種模式
- php中哪些函數是阻塞的
- 是否可以共用1個redis或mysql連接
- 如何在回調函數中訪問外部的變量
- 為什么不要send完后立即close
- 不同的Server程序實例間如何通信
- MySQL的連接池、異步、斷線重連
- 在php-fpm或apache中使用swoole
- 學習Swoole需要掌握哪些基礎知識
- 在phpinfo中有在php-m中沒有
- 同步阻塞與異步非阻塞選擇
- CURL發送POST請求服務器端超時
- 附錄
- 預定義常量
- 內核參數調優
- php四種回調寫法
- 守護進程程序常用數據結構
- swoole生命周期
- swoole_server中內存管理機制
- 使用jemalloc優化swoole內存分配性能
- Reactor、Worker、Task的關系
- Manager進程
- Swoole的實現
- Reactor線程
- 安裝擴展
- swoole-worker手冊
- swoole相關開源項目
- 寫在后面的話
- 版本更新記錄
- 4.0