Pereiti prie turinio

Fetch transportas

Numatytasis fetch(), esantis Phasis, veikia per PHP ext-curl — CURLOPT_FOLLOWLOCATION=false (specifikacijoje aprašytas peradresavimo ciklas vykdomas Phasis aplinkoje), o CURLOPT_PROGRESSFUNCTION tikrina AbortSignal. Daugeliui įterpimo atvejų to pakanka.

Visais kitais atvejais — tarpiniai serveriai, tinkintas DNS, esamas pagrindinės programos HTTP klientas, tinklo izoliavimas ar testų imitacijos — transportą galima prijungti.

Sąsaja

PHP
public function setFetchTransport(callable $transport): void

Jūsų iškviečiamasis objektas gauna:

PHP
function (array $request, ?\Phasis\Value\JsObject $signal): array

$request yra asociatyvusis masyvas:

Raktas Tipas Pastabos
method string Jau paverstas didžiosiomis raidėmis (GET, POST, …)
url string Išspręstas absoliutusis URL po URL analizatoriaus ir peradresavimų grandinės
headers list<list<string>> [name, value] poros; raidžių registras normalizuotas pagal specifikaciją; kelios reikšmės pateikiamos atskiromis poromis (Set-Cookie ir kt.)
body string Neapdoroti baitai. Metodams be turinio – tuščia eilutė.
redirect string "follow" / "error" / "manual" (jūsų transportas NETURI jų vykdyti — peradresavimų ciklas vykdomas Phasis)
timeout int Laiko pagal laikrodį biudžetas milisekundėmis. 0 = be apribojimo.
credentials string "omit" / "same-origin" / "include" — informaciniai; slapukai prijungiami atskirai per setCookieJar().

$signal yra null, jei užklausoje nebuvo signalo, kitu atveju tai JsObject, teikiantis aborted ir reason. Tikrinkite jį ilgų perdavimų metu.

Grąžinamos reikšmės struktūra:

PHP
return [
    'status'     => 200,                          // int
    'statusText' => 'OK',                         // string
    'headers'    => [['content-type', 'text/plain'], ['x-custom', '1']],
    'body'       => '...response bytes...',       // string
];

Jei transportas išmeta klaidą, Phasis ją pagauna ir atitinkamai apdoroja:

  • Jei Phasis\BuiltIn\Fetch\TransportException su $e->kind === "aborted", fetch atmetamas su AbortError DOMException.
  • kind === "timeout" → TypeError su klaidos pranešimu.
  • kind === "network-error" (numatytoji reikšmė) → TypeError.
  • Visa kita → TypeError su išimties pranešimu.

Pavyzdžiai

Guzzle

PHP
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;

$client = new Client(['allow_redirects' => false]);

$engine->setFetchTransport(function (array $req, $signal) use ($client) {
    try {
        $r = $client->request($req['method'], $req['url'], [
            'headers'     => collect($req['headers'])->groupBy(0)->map->pluck(1)->all(),
            'body'        => $req['body'],
            'timeout'     => max(1, $req['timeout'] / 1000.0),
            'http_errors' => false,
        ]);
    } catch (GuzzleException $e) {
        throw new \Phasis\BuiltIn\Fetch\TransportException($e->getMessage(), 'network-error');
    }
    $headers = [];
    foreach ($r->getHeaders() as $name => $values) {
        foreach ($values as $v) {
            $headers[] = [$name, $v];
        }
    }
    return [
        'status'     => $r->getStatusCode(),
        'statusText' => $r->getReasonPhrase(),
        'headers'    => $headers,
        'body'       => (string) $r->getBody(),
    ];
});

Symfony HttpClient

PHP
use Symfony\Component\HttpClient\HttpClient;

$client = HttpClient::create(['max_redirects' => 0]);

$engine->setFetchTransport(function (array $req, $signal) use ($client) {
    $headers = [];
    foreach ($req['headers'] as [$name, $value]) {
        $headers[$name][] = $value;
    }
    $r = $client->request($req['method'], $req['url'], [
        'headers'      => $headers,
        'body'         => $req['body'],
        'timeout'      => $req['timeout'] / 1000.0,
        'max_redirects'=> 0,
    ]);
    return [
        'status'     => $r->getStatusCode(),
        'statusText' => '',
        'headers'    => collect($r->getHeaders(false))
            ->flatMap(fn ($values, $name) => array_map(fn ($v) => [$name, $v], $values))
            ->values()->all(),
        'body'       => $r->getContent(false),
    ];
});

Viską draudžiantis transportas

PHP
$engine->setFetchTransport(function () {
    throw new \Phasis\BuiltIn\Fetch\TransportException(
        'network access disabled in this sandbox',
        'network-error',
    );
});

Taip kiekvienas fetch() iškvietimas atmetamas su TypeError. Naudinga izoliuojant naudotojo pateiktą JS.

Imitacija testams

PHP
$canned = [
    'https://api.example.com/users' => ['status' => 200, 'body' => '{"users":[]}'],
    'https://api.example.com/404'   => ['status' => 404, 'body' => 'not found'],
];

$engine->setFetchTransport(function (array $req) use ($canned) {
    $r = $canned[$req['url']] ?? ['status' => 500, 'body' => 'no mock'];
    return [
        'status'     => $r['status'],
        'statusText' => $r['status'] === 200 ? 'OK' : 'ERR',
        'headers'    => [['content-type', 'application/json']],
        'body'       => $r['body'],
    ];
});

Politikos kablys

Transportas vykdo užklausą, o politikos kablys sprendžia, ar ją apskritai vykdyti. Naudokite jį tik HTTPS taikomam valdymui, antraštėms įterpti, URL perrašyti, leidžiamų adresų sąrašams ar kiekvienam nuomininkui atskirai susietiems prisijungimo duomenims.

PHP
public function setFetchPolicy(callable $hook): void

Kablio signatūra: function (JsObject $request): ?JsObject. Grąžinus null, užklausa leidžiama nepakeista. Grąžinus Request, ji perrašoma. Išmetus klaidą, fetch užklausa atmetama su ja.

PHP
$allowedHosts = ['api.example.com', 'cdn.example.com'];

$engine->setFetchPolicy(function ($req) use ($allowedHosts) {
    $url = parse_url($req->get('url')->value);
    if (!in_array($url['host'] ?? '', $allowedHosts, true)) {
        throw new \RuntimeException("host not allowed: " . ($url['host'] ?? ''));
    }
    // Inject internal-only auth header
    $req->get('headers')->call('set', 'X-Internal-Token', $secret);
    return null;
});

Politikos kablys vykdomas prieš transportą, todėl net ir klaidingas ar nepatikimas transportas negali jo apeiti.

Numatytosios elgsenos santrauka

Sritis Numatytoji reikšmė
Transportas CurlTransport (PHP ext-curl)
Peradresavimai Pagal specifikaciją vykdoma iki 20 peradresavimų. redirect: "manual" grąžina peradresavimo Response su type: "opaqueredirect".
Skirtasis laikas 30 s pagal laikrodį, 10 s prisijungimui
TLS tikrinimas CURLOPT_SSL_VERIFYPEER = true (atsisakyti negalima — pakeiskite transportą)
User-Agent Phasis/0.1 įterpiamas tik tada, jei nenustatytas
Slapukai Neišsaugomi. Įjunkite per setCookieJar().
Politikos kablys Nėra. Visos užklausos leidžiamos, nebent aiškiai uždraustos.
AbortSignal Skrydžio metu paisoma per curl eigos atgalinio iškvietimo patikrą.

Taip pat žr.