Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
Yurunsoft committed Mar 27, 2020
2 parents 1024c84 + 25dc771 commit 44d538a
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 65 deletions.
6 changes: 6 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ dist: trusty

matrix:
include:
- php: '5.5'
env: PHPUNIT_VERSION="4"
- php: '5.6'
env: PHPUNIT_VERSION="5"
- php: '7.0'
env: SWOOLE_VERSION="v4.3.6" PHPUNIT_VERSION="6"
- php: '7.1'
env: SWOOLE_VERSION="v4.3.6" PHPUNIT_VERSION="7"
- php: '7.2'
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ API 文档:[https://apidoc.gitee.com/yurunsoft/YurunHttp](https://apidoc.gitee

> 每个小版本的更新日志请移步到 Release 查看
v4.2.0 重构 Swoole 处理器,并发请求性能大幅提升 (PHP 版本依赖降为 >= 5.5)

v4.1.0 实现智能识别场景,自动选择适合 Curl/Swoole 环境的处理器

v4.0.0 新增支持 `Swoole` 并发批量请求 (PHP >= 7.1)
Expand Down Expand Up @@ -51,7 +53,7 @@ v1.0-1.3 初期版本迭代
```json
{
"require": {
"yurunsoft/yurun-http": "^4.1.0"
"yurunsoft/yurun-http": "^4.2.0"
}
}
```
Expand Down
5 changes: 2 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
"name": "yurunsoft/yurun-http",
"description": "YurunHttp 是开源的 PHP HTTP 类库,支持链式操作,简单易用。支持 Curl、Swoole,支持 Http、Http2、WebSocket!",
"require": {
"php": ">=7.1.0",
"psr/http-message": "~1.0",
"yurunsoft/swoole-co-pool": "^1.1.0"
"php": ">=5.5.0",
"psr/http-message": "~1.0"
},
"require-dev": {
"swoft/swoole-ide-helper": "~2.0",
Expand Down
2 changes: 1 addition & 1 deletion src/YurunHttp.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ abstract class YurunHttp
/**
* 版本号
*/
const VERSION = '4.1';
const VERSION = '4.2';

/**
* 设置默认处理器类
Expand Down
25 changes: 25 additions & 0 deletions src/YurunHttp/Attributes.php
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,11 @@ abstract class Attributes
*/
const HTTP2_PIPELINE = 'http2_pipeline';

/**
* 重试计数
*/
const PRIVATE_RETRY_COUNT = '__retryCount';

/**
* 重定向计数
*/
Expand All @@ -178,4 +183,24 @@ abstract class Attributes
*/
const PRIVATE_WEBSOCKET = '__websocket';

/**
* Http2 流ID
*/
const PRIVATE_HTTP2_STREAM_ID = '__http2StreamId';

/**
* 是否为 Http2
*/
const PRIVATE_IS_HTTP2 = '__isHttp2';

/**
* 是否为 WebSocket
*/
const PRIVATE_IS_WEBSOCKET = '__isWebSocket';

/**
* 连接对象
*/
const PRIVATE_CONNECTION = '__connection';

}
5 changes: 5 additions & 0 deletions src/YurunHttp/Handler/Curl.php
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,11 @@ private function getResponse($handler, $curlResult, $isDownload, $receiveHeaders
$headerSize = curl_getinfo($handler, CURLINFO_HEADER_SIZE);
$headerContent = substr($curlResult, 0, $headerSize);
$body = substr($curlResult, $headerSize);
// PHP 7.0.0开始substr()的 string 字符串长度与 start 相同时将返回一个空字符串。在之前的版本中,这种情况将返回 FALSE 。
if(false === $body)
{
$body = '';
}

// body
$result = new Response($body, curl_getinfo($handler, CURLINFO_HTTP_CODE));
Expand Down
151 changes: 91 additions & 60 deletions src/YurunHttp/Handler/Swoole.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
use Yurun\Util\YurunHttp\Exception\WebSocketException;
use Yurun\Util\YurunHttp\Handler\Swoole\HttpConnectionManager;
use Yurun\Util\YurunHttp\Handler\Swoole\Http2ConnectionManager;
use function Yurun\Swoole\Coroutine\batch;

class Swoole implements IHandler
{
Expand Down Expand Up @@ -180,6 +179,22 @@ public function buildRequest($request, $connection, &$http2Request)
* @return bool
*/
public function send($request)
{
$deferRequest = $this->sendDefer($request);
if($request->getAttribute(Attributes::PRIVATE_IS_HTTP2) && $request->getAttribute(Attributes::HTTP2_NOT_RECV))
{
return true;
}
return !!$this->recvDefer($deferRequest);
}

/**
* 发送请求,但延迟接收
*
* @param \Yurun\Util\YurunHttp\Http\Request $request
* @return \Yurun\Util\YurunHttp\Http\Request
*/
public function sendDefer($request)
{
if([] !== ($queryParams = $request->getQueryParams()))
{
Expand All @@ -196,73 +211,86 @@ public function send($request)
$connection = $this->httpConnectionManager->getConnection($uri->getHost(), Uri::getServerPort($uri), 'https' === $uri->getScheme() || 'wss' === $uri->getScheme());
$connection->setDefer(true);
}
$redirectCount = $request->getAttribute(Attributes::PRIVATE_REDIRECT_COUNT, 0);
$statusCode = 0;
$isWebSocket = $request->getAttribute(Attributes::PRIVATE_WEBSOCKET);
$retry = $request->getAttribute(Attributes::RETRY, 0);
for($i = 0; $i <= $retry; ++$i)
// 构建
$this->buildRequest($request, $connection, $http2Request);
// 发送
$path = $uri->getPath();
if('' === $path)
{
// 构建
$this->buildRequest($request, $connection, $http2Request);
// 发送
$path = $uri->getPath();
if('' === $path)
{
$path = '/';
}
$query = $uri->getQuery();
if('' !== $query)
$path = '/';
}
$query = $uri->getQuery();
if('' !== $query)
{
$path .= '?' . $query;
}
if($isWebSocket)
{
if($isHttp2)
{
$path .= '?' . $query;
throw new \RuntimeException('Http2 swoole handler does not support websocket');
}
if($isWebSocket)
if(!$connection->upgrade($path))
{
if($isHttp2)
{
throw new \RuntimeException('Http2 swoole handler does not support websocket');
}
if(!$connection->upgrade($path))
{
throw new WebSocketException(sprintf('WebSocket connect faled, error: %s, errorCode: %s', swoole_strerror($connection->errCode), $connection->errCode), $connection->errCode);
}
throw new WebSocketException(sprintf('WebSocket connect faled, error: %s, errorCode: %s', swoole_strerror($connection->errCode), $connection->errCode), $connection->errCode);
}
else if(null === ($saveFilePath = $request->getAttribute(Attributes::SAVE_FILE_PATH)))
}
else if(null === ($saveFilePath = $request->getAttribute(Attributes::SAVE_FILE_PATH)))
{
if($isHttp2)
{
if($isHttp2)
{
$result = $connection->send($http2Request);
}
else
{
$connection->execute($path);
}
$result = $connection->send($http2Request);
$request = $request->withAttribute(Attributes::PRIVATE_HTTP2_STREAM_ID, $result);
}
else
{
if($isHttp2)
{
throw new \RuntimeException('Http2 swoole handler does not support download file');
}
$connection->download($path, $saveFilePath);
}
if($isHttp2 && $request->getAttribute(Attributes::HTTP2_NOT_RECV))
{
return $result;
$connection->execute($path);
}
$this->getResponse($request, $connection, $isWebSocket, $isHttp2);
$statusCode = $this->result->getStatusCode();
// 状态码为5XX或者0才需要重试
if(!(0 === $statusCode || (5 === (int)($statusCode/100))))
}
else
{
if($isHttp2)
{
break;
throw new \RuntimeException('Http2 swoole handler does not support download file');
}
$connection->download($path, $saveFilePath);
}

return $request->withAttribute(Attributes::PRIVATE_IS_HTTP2, $isHttp2)
->withAttribute(Attributes::PRIVATE_IS_WEBSOCKET, $isHttp2)
->withAttribute(Attributes::PRIVATE_CONNECTION, $connection);
}

/**
* 延迟接收
*
* @param \Yurun\Util\YurunHttp\Http\Request $request
* @return \Yurun\Util\YurunHttp\Http\Response
*/
public function recvDefer($request)
{
/** @var \Swoole\Coroutine\Http\Client|\Swoole\Coroutine\Http2\Client $connection */
$connection = $request->getAttribute(Attributes::PRIVATE_CONNECTION);
$retryCount = $request->getAttribute(Attributes::PRIVATE_RETRY_COUNT, 0);
$redirectCount = $request->getAttribute(Attributes::PRIVATE_REDIRECT_COUNT, 0);
$isHttp2 = '2.0' === $request->getProtocolVersion();
$isWebSocket = $request->getAttribute(Attributes::PRIVATE_WEBSOCKET);
$this->getResponse($request, $connection, $isWebSocket, $isHttp2);
$statusCode = $this->result->getStatusCode();
// 状态码为5XX或者0才需要重试
if((0 === $statusCode || (5 === (int)($statusCode/100))) && $retryCount < $request->getAttribute(Attributes::RETRY, 0))
{
$request = $request->withAttribute(Attributes::RETRY, ++$retryCount);
$deferRequest = $this->sendDefer($request);
return $this->recvDefer($deferRequest);
}
if(!$isWebSocket && $statusCode >= 300 && $statusCode < 400 && $request->getAttribute(Attributes::FOLLOW_LOCATION, true))
{
if(++$redirectCount <= ($maxRedirects = $request->getAttribute(Attributes::MAX_REDIRECTS, 10)))
{
// 自己实现重定向
$uri = $this->parseRedirectLocation($this->result->getHeaderLine('location'), $uri);
$uri = $this->parseRedirectLocation($this->result->getHeaderLine('location'), $request->getUri());
if(in_array($statusCode, [301, 302, 303]))
{
$method = 'GET';
Expand All @@ -276,11 +304,11 @@ public function send($request)
else
{
$this->result = $this->result->withErrno(-1)
->withError(sprintf('Maximum (%s) redirects followed', $maxRedirects));
->withError(sprintf('Maximum (%s) redirects followed', $maxRedirects));
return false;
}
}
return true;
return $this->result;
}

/**
Expand Down Expand Up @@ -556,17 +584,20 @@ public function getHttp2ConnectionManager()
*/
public function coBatch($requests, $timeout = null)
{
$callbacks = [];
foreach($requests as $k => $request)
$handlers = [];
$results = [];
foreach($requests as $i => &$request)
{
$results[$i] = null;
$handlers[$i] = $handler = new Swoole;
$request = $handler->sendDefer($request);
}
unset($request);
foreach($requests as $i => $request)
{
$callbacks[$k] = function() use($request){
$swooleHandler = new Swoole;
$swooleHandler->send($request);
$response = $swooleHandler->recv();
return $response;
};
$results[$i] = $handlers[$i]->recvDefer($request);
}
return batch($callbacks, $timeout ?? -1);
return $results;
}

}

0 comments on commit 44d538a

Please sign in to comment.