본문으로 건너뛰기

쿠키 저장소

기본적으로 Phasis의 fetch()은 응답의 Set-Cookie을 무시하고 요청에 Cookie 헤더를 보내지 않습니다. 서버 측 임베딩에 적합한 기본값입니다. 일반적으로 한 사용자의 응답이 다른 사용자의 요청에 영향을 주지 않도록 해야 합니다.

세션 상태에 따라 달라지는 흐름을 실행하거나, 로그인 뒤에서 데이터를 가져오거나, 테스트에서 브라우저 동작을 재현하는 등 쿠키가 필요하다면 $engine->setCookieJar($jar)으로 저장소를 연결하세요.

인터페이스

저장소는 다음 두 메서드에 응답하는 객체라면 무엇이든 됩니다:

코드
get(url: string): string         // returns a "Cookie:" header value, e.g. "sid=abc; pref=dark"
set(url: string, header: string): void   // receives one Set-Cookie line

PHP 객체와 일치하는 멤버를 가진 JS 측 JsObjects 모두 사용할 수 있습니다. null을 전달하면 저장소가 비워집니다.

Phasis은 요청이 이동하는 각 단계마다 get(url)을 호출합니다(따라서 다른 호스트로 리디렉션되면 새 쿠키를 가져옵니다). 응답의 각 Set-Cookie 헤더마다 set(url, line)를 호출합니다. 도메인 일치, 경로 범위, 만료, SameSite, Secure 같은 쿠키 정책은 저장소가 담당하며 Phasis의 책임은 아닙니다.

메모리 내 저장소(테스트)

PHP
final class MemoryJar
{
    /** @var array<string, array<string, string>> host → name → "name=value" */
    private array $store = [];

    public function get(string $url): string
    {
        $host = parse_url($url, PHP_URL_HOST) ?? '';
        return implode('; ', $this->store[$host] ?? []);
    }

    public function set(string $url, string $header): void
    {
        $host = parse_url($url, PHP_URL_HOST) ?? '';
        [$nv] = explode(';', $header, 2);
        [$name, $value] = explode('=', trim($nv), 2) + ['', ''];
        if ($name !== '') {
            $this->store[$host][$name] = "$name=$value";
        }
    }
}

$engine->setCookieJar(new MemoryJar());

정상 경로 테스트 픽스처로는 충분하지만 Domain=, Path=, Expires= 및 Secure/HttpOnly/SameSite 속성은 무시합니다. 신뢰 경계를 넘는 작업에는 사용하지 마세요.

Symfony BrowserKit

이미 Symfony의 HTTP 라이브러리를 설치했다면 BrowserKit\CookieJar가 정책을 올바르게 처리합니다.

PHP
use Symfony\Component\BrowserKit\CookieJar as BrowserCookieJar;
use Symfony\Component\BrowserKit\Cookie;

final class SymfonyJarAdapter
{
    public function __construct(private BrowserCookieJar $jar) {}

    public function get(string $url): string
    {
        $cookies = $this->jar->allValues($url);
        return implode('; ', array_map(
            fn ($n, $v) => "$n=$v",
            array_keys($cookies),
            array_values($cookies),
        ));
    }

    public function set(string $url, string $header): void
    {
        $cookie = Cookie::fromString($header, $url);
        $this->jar->set($cookie);
    }
}

$engine->setCookieJar(new SymfonyJarAdapter(new BrowserCookieJar()));

JS 측 저장소

저장소가 JS 측에 있는 경우(예를 들어 JavaScript에서 확인하거나 초기화하려는 경우) JS 객체를 통해 연결하세요:

JavaScript
const jar = new Map();
$jar.get = (url) => Array.from(jar.entries()).map(([k, v]) => `${k}=${v}`).join('; ');
$jar.set = (url, header) => {
  const [nv] = header.split(';');
  const [name, value] = nv.split('=');
  jar.set(name.trim(), value.trim());
};
PHP
$engine->eval($script);
$engine->setCookieJar($engine->eval('$jar'));

수신자가 PHP 객체든 JsObject든 get/set 메서드가 동일하게 호출됩니다.

요청별 범위

저장소는 영역에 속하며, setCookieJar(null)로 비울 때까지 모든 fetch()에 걸쳐 유지됩니다. 저장소를 단일 요청 흐름에만 적용하려면 명시적으로 설정하세요:

PHP
$engine->setCookieJar($jar);
$engine->eval('await runLoginFlow()');
$engine->setCookieJar(null);

PHP에서 확인하기

$engine->getCookieJar()은 전달된 값을 그대로 반환하므로 테스트에서 단언할 때 유용합니다.

PHP
$jar = new MemoryJar();
$engine->setCookieJar($jar);
$engine->eval('await fetch("https://api.example.com/login", { method: "POST" })');

assertNotEmpty($engine->getCookieJar()->get('https://api.example.com/'));

관련 항목

  • Fetch 전송 계층 — 쿠키 저장소는 Phasis의 리디렉션 루프 내부에서 작동하며 설치된 전송 계층 위에 적용됩니다.
  • 웹 API(WPT) — 쿠키 동작을 다루는 Fetch Pack 테스트.