workerman/http-client
설명
workerman/http-client은 비동기 http 클라이언트 구성 요소입니다. 모든 요청 응답은 비동기 비차단이며, 내장된 연결 풀, 메시지 요청 및 응답은 PSR7 규격을 준수합니다.
설치:
composer require workerman/http-client
예제:
get 및 post 요청 사용법
use Workerman\Worker;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker();
$worker->onWorkerStart = function () {
$http = new Workerman\Http\Client();
$http->get('https://example.com/', function ($response) {
var_dump($response->getStatusCode());
echo $response->getBody();
}, function ($exception) {
echo $exception;
});
$http->post('https://example.com/', ['key1' => 'value1', 'key2' => 'value2'], function ($response) {
var_dump($response->getStatusCode());
echo $response->getBody();
}, function ($exception) {
echo $exception;
});
$http->request('https://example.com/', [
'method' => 'POST',
'version' => '1.1',
'headers' => ['Connection' => 'keep-alive'],
'data' => ['key1' => 'value1', 'key2' => 'value2'],
'success' => function ($response) {
echo $response->getBody();
},
'error' => function ($exception) {
echo $exception;
}
]);
};
Worker::runAll();
파일 업로드
<?php
use Workerman\Worker;
require_once 'vendor/autoload.php';
$worker = new Worker();
$worker->onWorkerStart = function () {
$http = new Workerman\Http\Client();
// 파일 업로드
$multipart = new \Workerman\Psr7\MultipartStream([
[
'name' => 'file',
'contents' => fopen(__FILE__, 'r')
],
[
'name' => 'json',
'contents' => json_encode(['a'=>1, 'b'=>2])
]
]);
$boundary = $multipart->getBoundary();
$http->request('http://127.0.0.1:8787', [
'method' => 'POST',
'version' => '1.1',
'headers' => ['Connection' => 'keep-alive', 'Content-Type' => "multipart/form-data; boundary=$boundary"],
'data' => $multipart,
'success' => function ($response) {
echo $response->getBody();
},
'error' => function ($exception) {
echo $exception;
}
]);
};
Worker::runAll();
progress 스트리밍 반환
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Workerman\Connection\TcpConnection;
use Workerman\Http\Client;
use Workerman\Protocols\Http\Chunk;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols\Http\Response;
use Workerman\Worker;
$worker = new Worker('http://0.0.0.0:1234');
$worker->onMessage = function (TcpConnection $connection, Request $request) {
$http = new Client();
$http->request('https://api.ai.com/v1/chat/completions', [
'method' => 'POST',
'data' => json_encode([
'model' => 'gpt-3.5-turbo',
'temperature' => 1,
'stream' => true,
'messages' => [['role' => 'user', 'content' => 'hello']],
]),
'headers' => [
'Content-Type' => 'application/json',
'Authorization' => 'Bearer sk-xxx',
],
'progress' => function($buffer) use ($connection) {
$connection->send(new Chunk($buffer));
},
'success' => function($response) use ($connection) {
$connection->send(new Chunk('')); // 빈 청크를 보내서 응답 종료 표시
},
]);
$connection->send(new Response(200, [
//"Content-Type" => "application/octet-stream",
"Transfer-Encoding" => "chunked",
], ''));
};
Worker::runAll();
옵션
<?php
require __DIR__ . '/vendor/autoload.php';
use Workerman\Worker;
$worker = new Worker();
$worker->onWorkerStart = function(){
$options = [
'max_conn_per_addr' => 128, // 각 도메인에서 최대 유지할 수 있는 동시 연결 수
'keepalive_timeout' => 15, // 연결이 얼마나 오랫동안 통신이 없어야 종료될지
'connect_timeout' => 30, // 연결 초과 시간
'timeout' => 30, // 요청 후 응답을 기다리는 초과 시간
];
$http = new Workerman\Http\Client($options);
$http->get('http://example.com/', function($response){
var_dump($response->getStatusCode());
echo $response->getBody();
}, function($exception){
echo $exception;
});
};
Worker::runAll();
코루틴 사용법
주의
코루틴 사용법은 workerman>=5.1, http-client>=3.0이 필요하며,swoole또는swow확장을 설치하거나composer require revolt/event-loop를 설치하여 Fiber 드라이버를 지원해야 합니다.
use Workerman\Worker;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker();
$worker->eventLoop = \Workerman\Events\Swoole::class; // 또는 \Workerman\Events\Swow::class 또는 \Workerman\Events\Fiber::class
$worker->onWorkerStart = function () {
$http = new Workerman\Http\Client();
$response = $http->get('https://example.com/');
var_dump($response->getStatusCode());
echo $response->getBody();
$response = $http->post('https://example.com/', ['key1' => 'value1', 'key2' => 'value2']);
var_dump($response->getStatusCode());
echo $response->getBody();
$response = $http->request('https://example.com/', [
'method' => 'POST',
'version' => '1.1',
'headers' => ['Connection' => 'keep-alive'],
'data' => ['key1' => 'value1', 'key2' => 'value2'],
]);
echo $response->getBody();
};
Worker::runAll();
콜백 함수를 설정하지 않으면 클라이언트는 동기 방식으로 비동기 요청 결과를 반환하며, 요청 과정은 현재 프로세스를 차단하지 않으므로 여러 요청을 동시에 처리할 수 있습니다.
주의사항:
-
프로젝트는 먼저
require __DIR__ . '/vendor/autoload.php';를 로드해야 합니다. -
모든 비동기 코드는 workerman 시작 후 실행 환경에서만 실행할 수 있습니다.
-
workerman 기반으로 개발된 모든 프로젝트를 지원합니다. 여기에는 Webman, GatewayWorker, PHPSocket.io 등이 포함됩니다.
-
클라이언트 객체를 최대한 저장하여 재사용하는 것이 좋습니다. 이렇게 하면 연결 풀을 최대한 활용하여 성능을 향상시킬 수 있으며 매번
new Workerman\Http\Client()로 객체를 반복 생성하는 것을 피해야 합니다.
webman에서 사용법
webman에서 비동기 http 요청을 사용하고 결과를 프론트엔드로 반환하려면 다음 사용법을 참조하세요.
<?php
namespace app\controller;
use support\Request;
use support\Response;
use Workerman\Protocols\Http\Chunk;
class IndexController
{
public function index(Request $request)
{
// 클라이언트 객체를 저장하여 재사용하면 성능이 크게 향상됩니다.
static $http;
$connection = $request->connection;
$http = $http ?: new \Workerman\Http\Client();
$http->get('https://example.com/', function ($response) use ($connection) {
$connection->send(new Chunk($response->getBody()));
$connection->send(new Chunk('')); // 빈 청크를 보내서 응답 종료 표시
});
return response()->withHeaders([
"Transfer-Encoding" => "chunked",
]);
}
}
위 사용법은 먼저 클라이언트에 chunked http 헤더를 반환한 후 데이터를 청크 방식으로 클라이언트에 전송합니다. 물론 위의 코루틴 사용법을 참조할 수도 있습니다.
주의
위 코드는 클라이언트 객체를 재사용하기 위해 메서드 범위의 정적 변수에 저장했습니다. 실제로 클래스의 정적 멤버나 전역 객체에 저장할 수도 있습니다.