설명

workerman은 4.x 버전부터 HTTP 서비스에 대한 지원을 강화했습니다. 요청 클래스, 응답 클래스, 세션 클래스 및 SSE를 도입했습니다. workerman의 HTTP 서비스를 사용하고 싶다면 workerman 4.x 또는 그 이후의 버전을 사용하는 것을 강력하게 권장합니다.

다음은 workerman 4.x 버전의 사용법으로, workerman 3.x와 호환되지 않습니다.

주의

  • 청크 또는 SSE 응답을 전송하지 않는 한, 하나의 요청에서 여러 번 응답을 전송할 수 없습니다. 즉, 하나의 요청에서 $connection->send()를 여러 번 호출하는 것은 허용되지 않습니다.
  • 각 요청은 최종적으로 한 번 $connection->send()를 호출하여 응답을 전송해야 하며, 그렇지 않으면 클라이언트는 계속 대기하게 됩니다.

빠른 응답

HTTP 상태 코드(기본값 200)를 변경할 필요가 없거나, 사용자 정의 헤더, 쿠키가 필요하지 않을 경우 문자열을 클라이언트로 직접 전송하여 응답을 완료할 수 있습니다.

예제

use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';

$worker = new Worker('http://0.0.0.0:8080');

$worker->onMessage = function(TcpConnection $connection, Request $request)
{
    // 클라이언트에게 this is body를 직접 전송
    $connection->send("this is body");
};

// worker 실행
Worker::runAll();

상태 코드 변경

사용자 정의 상태 코드, 헤더, 쿠키가 필요할 경우 Workerman\Protocols\Http\Response 응답 클래스를 사용해야 합니다. 예를 들어, 아래 예제는 경로가 /404일 경우 404 상태 코드를 반환하며, 본문 내용은 <h1>죄송합니다. 파일이 존재하지 않습니다.</h1>입니다.

예제

use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols\Http\Response;
require_once __DIR__ . '/vendor/autoload.php';

$worker = new Worker('http://0.0.0.0:8080');

$worker->onMessage = function(TcpConnection $connection, Request $request)
{
    if ($request->path() === '/404') {
        $connection->send(new Response(404, [], '<h1>죄송합니다. 파일이 존재하지 않습니다.</h1>'));
    } else {
        $connection->send('this is body');
    }
};

// worker 실행
Worker::runAll();

Response 클래스가 이미 초기화된 후 상태 코드를 변경하려면 아래의 방법을 사용합니다.

$response = new Response(200);
$response->withStatus(404);
$connection->send($response);

헤더 전송

헤더를 전송하려면 Workerman\Protocols\Http\Response 응답 클래스를 사용해야 합니다.

예제

use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols\Http\Response;
require_once __DIR__ . '/vendor/autoload.php';

$worker = new Worker('http://0.0.0.0:8080');

$worker->onMessage = function(TcpConnection $connection, Request $request)
{
    $response = new Response(200, [
        'Content-Type' => 'text/html',
        'X-Header-One' => '헤더 값'
    ], 'this is body');
    $connection->send($response);
};

// worker 실행
Worker::runAll();

Response 클래스가 이미 초기화된 후 헤더를 추가하거나 변경하려면 아래의 방법을 사용합니다.

$response = new Response(200);
// 하나의 헤더 추가 또는 변경
$response->header('Content-Type', 'text/html');
// 여러 헤더 추가 또는 변경
$response->withHeaders([
    'Content-Type' => 'application/json',
    'X-Header-One' => '헤더 값'
]);
$connection->send($response);

리디렉션

use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols\Http\Response;
require_once __DIR__ . '/vendor/autoload.php';

$worker = new Worker('http://0.0.0.0:8080');

$worker->onMessage = function(TcpConnection $connection, Request $request)

$worker = new Worker('http://0.0.0.0:8080');
$worker->onMessage = function($connection, $request)
{
    $location = '/test_location';
    $response = new Response(302, ['Location' => $location]);
    $connection->send($response);
};
Worker::runAll();

쿠키 전송

쿠키를 전송하려면 Workerman\Protocols\Http\Response 응답 클래스를 사용해야 합니다.

예제

use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols\Http\Response;
require_once __DIR__ . '/vendor/autoload.php';

$worker = new Worker('http://0.0.0.0:8080');

$worker->onMessage = function(TcpConnection $connection, Request $request)
{
    $response = new Response(200, [], 'this is body');
    $response->cookie('name', 'tom');
    $connection->send($response);
};

// worker 실행
Worker::runAll();

파일 전송

파일을 전송하려면 Workerman\Protocols\Http\Response 응답 클래스를 사용해야 합니다.

파일을 전송할 때는 다음과 같은 방법을 사용합니다.

$response = (new Response())->withFile($file);
$connection->send($response);
  • workerman은 대용량 파일 전송을 지원합니다.
  • 큰 파일(2M 초과)의 경우, workerman은 전체 파일을 한 번에 메모리에 읽지 않고, 적절한 시점에 파일을 분할하여 읽고 전송합니다.
  • workerman은 클라이언트의 수신 속도에 따라 파일 읽기 및 전송 속도를 최적화하여, 가장 빠르게 파일을 전송하는 동시에 메모리 사용을 최소화합니다.
  • 데이터 전송은 논블로킹 방식이며, 다른 요청 처리에 영향을 주지 않습니다.
  • 파일 전송 시 자동으로 Last-Modified 헤더를 추가하여, 다음 요청 시 서버가 304 응답을 전송하여 파일 전송을 절약하고 성능을 향상시킵니다.
  • 전송된 파일은 자동으로 적절한 Content-Type 헤더를 사용하여 브라우저에 전송됩니다.
  • 파일이 존재하지 않을 경우, 자동으로 404 응답으로 전환됩니다.

예제

use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols\Http\Response;
require_once __DIR__ . '/vendor/autoload.php';

$worker = new Worker('http://0.0.0.0:8080');

$worker->onMessage = function(TcpConnection $connection, Request $request)
{
    $file = '/your/path/of/file';
    // if-modified-since 헤더를 확인하여 파일이 수정되었는지 판단
    if (!empty($if_modified_since = $request->header('if-modified-since'))) {
        $modified_time = date('D, d M Y H:i:s',  filemtime($file)) . ' ' . \date_default_timezone_get();
        // 파일이 수정되지 않았다면 304 반환
        if ($modified_time === $if_modified_since) {
            $connection->send(new Response(304));
            return;
        }
    }
    // 파일이 수정되었거나 if-modified-since 헤더가 없으면 파일 전송
    $response = (new Response())->withFile($file);
    $connection->send($response);
};

// worker 실행
Worker::runAll();

HTTP 청크 데이터 전송

  • 반드시 Transfer-Encoding: chunked 헤더를 포함한 Response 응답을 클라이언트에 먼저 전송해야 합니다.
  • 후속 청크 데이터는 Workerman\Protocols\Http\Chunk 클래스를 사용하여 전송합니다.
  • 최종적으로 빈 청크를 전송하여 응답을 종료해야 합니다.

예제

use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols\Http\Response;
use Workerman\Protocols\Http\Chunk;
require_once __DIR__ . '/vendor/autoload.php';

$worker = new Worker('http://0.0.0.0:8080');

$worker->onMessage = function(TcpConnection $connection, Request $request)
{
    // 먼저 Transfer-Encoding: chunked 헤더가 있는 Response 응답을 전송
    $connection->send(new Response(200, array('Transfer-Encoding' => 'chunked'), 'hello'));
    // 후속 청크 데이터는 Workerman\Protocols\Http\Chunk 클래스를 사용하여 전송
    $connection->send(new Chunk('첫 번째 데이터'));
    $connection->send(new Chunk('두 번째 데이터'));
    $connection->send(new Chunk('세 번째 데이터'));
    // 마지막으로 빈 청크를 전송하여 응답 종료
    $connection->send(new Chunk(''));
};

// worker 실행
Worker::runAll();