Pāriet uz saturu

Fetch transports

Noklusējuma fetch() Phasis darbojas ar PHP ext-curl — CURLOPT_FOLLOWLOCATION=false (specifikācijas novirzīšanas cikls darbojas Phasis vidē), kur CURLOPT_PROGRESSFUNCTION pārbauda AbortSignal. Lielākajai daļai iegulšanas gadījumu tas ir piemērots.

Visiem pārējiem gadījumiem — starpniekserveriem, pielāgotam DNS, resursdatora lietotnes esošajam HTTP klientam, tīkla izolācijai un testu imitācijām — transportu var nomainīt.

Saskarne

PHP
public function setFetchTransport(callable $transport): void

Jūsu izsaucamā funkcija saņem:

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

$request ir asociatīvs masīvs:

Atslēga Tips Piezīmes
method string Jau pārveidots uz lielajiem burtiem (GET, POST, …)
url string Atrisināts absolūtais URL pēc URL parsētāja un novirzīšanas ķēdes
headers list<list<string>> [name, value] pāri; reģistrs normalizēts atbilstoši specifikācijai; vairāku vērtību ieraksti ir atsevišķi pāri (Set-Cookie u. c.)
body string Neapstrādāti baiti. Tukša virkne metodēm bez pamatdaļas.
redirect string "follow" / "error" / "manual" (jūsu transportam tiem NAV jāseko — novirzīšanas cikls darbojas Phasis)
timeout int Sienas pulksteņa laika limits milisekundēs. 0 = bez ierobežojuma.
credentials string "omit" / "same-origin" / "include" — informatīvi; sīkdatnes tiek piesaistītas atsevišķi, izmantojot setCookieJar().

$signal ir null, ja pieprasījumam nav norādīts signāls; pretējā gadījumā tas ir JsObject, kas atklāj aborted un reason. Ilgu pārsūtīšanas darbību laikā periodiski pārbaudiet to.

Atgriežamā vērtība:

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

Ja transports izmet kļūdu, Phasis to uztver un pārveido:

  • Ja Phasis\BuiltIn\Fetch\TransportException ar $e->kind === "aborted" → fetch tiek noraidīts ar AbortError DOMException.
  • kind === "timeout" → TypeError ar ziņojumu.
  • kind === "network-error" (pēc noklusējuma) → TypeError.
  • Jebkas cits → TypeError ar izņēmuma ziņojumu.

Piemēri

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),
    ];
});

Visu aizliegt

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

Tādējādi katrs fetch() izsaukums tiek noraidīts ar TypeError. Noder lietotāja sniegta JS izolēšanai.

Tests ar aizstājēju

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'],
    ];
});

Politikas āķis

Transports izpilda pieprasījumu; politikas āķis nosaka, vai to vispār izpildīt. Izmantojiet to, lai piemērotu tikai HTTPS ierobežojumus, ievietotu galvenes, pārveidotu URL, izveidotu atļauto sarakstu vai piesaistītu katram nomniekam savus akreditācijas datus.

PHP
public function setFetchPolicy(callable $hook): void

Āķa signatūra: function (JsObject $request): ?JsObject. Atgriežot null, pieprasījums tiek atļauts bez izmaiņām. Atgriežot Request, pieprasījums tiek pārrakstīts. Izmetot kļūdu, izgūšana tiek noraidīta ar izmesto kļūdu.

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;
});

Politikas āķis darbojas pirms transporta, tāpēc pat kļūdains vai neuzticams transports to nevar apiet.

Noklusējuma darbības kopsavilkums

Aspekts Noklusējums
Transports CurlTransport (PHP ext-curl)
Novirzīšana Saskaņā ar specifikāciju seko ne vairāk kā 20 novirzīšanām. redirect: "manual" atgriež novirzīšanas Response ar type: "opaqueredirect".
Taimauts 30 s sienas pulksteņa laiks, 10 s savienojumam
TLS pārbaude CURLOPT_SSL_VERIFYPEER = true (atteikties no tās nevar — aizstājiet transportu)
User-Agent Phasis/0.1 tiek ievietots tikai tad, ja nav iestatīts
Sīkdatnes Netiek saglabātas. Izmantojiet setCookieJar(), lai tās iespējotu.
Politikas āķis Nav. Visi pieprasījumi ir atļauti, ja vien tie nav skaidri aizliegti.
AbortSignal Pārsūtīšanas laikā tiek ievērots, periodiski pārbaudot curl progresa atzvanīšanas funkciju.

Skatiet arī