Prenos Fetch
Privzeti fetch() v Phasis deluje prek PHP ext-curl — CURLOPT_FOLLOWLOCATION=false (preusmeritvena zanka specifikacije deluje v okolju Phasis) in CURLOPT_PROGRESSFUNCTION preverja AbortSignal. Za večino vdelav je to primerno.
Za vse drugo — posredniške strežnike, lasten DNS, obstoječi odjemalec HTTP gostiteljske aplikacije, omrežno peskovnikovanje ali posnemanje v testih — je prenos prilagodljiv.
Vmesnik
public function setFetchTransport(callable $transport): void
Vaša klicna funkcija prejme:
function (array $request, ?\Phasis\Value\JsObject $signal): array
$request je asociativna tabela:
| Ključ | Vrsta | Opombe |
|---|---|---|
method |
string |
Že zapisano z velikimi črkami (GET, POST, …) |
url |
string |
Razrešen absolutni URL po razčlenjevalniku URL in verigi preusmeritev |
headers |
list<list<string>> |
Pari vrednosti [name, value]; velikost črk normalizira specifikacija; večvrednostni vnosi so ločeni pari (Set-Cookie itd.) |
body |
string |
Neobdelani bajti. Prazen niz za metode brez telesa. |
redirect |
string |
"follow" / "error" / "manual" (vaš prenos jim NE sme slediti — preusmeritvena zanka deluje v Phasis) |
timeout |
int |
Proračun po stenski uri v milisekundah. 0 = brez omejitve. |
credentials |
string |
"omit" / "same-origin" / "include" — zgolj informativno; piškotki se povežejo ločeno prek setCookieJar(). |
$signal je null, če zahtevi ni bil dodeljen signal, sicer pa JsObject z vrednostma aborted in reason. Med dolgotrajnimi prenosi ga redno preverjajte.
Oblika vrnjene vrednosti:
return [
'status' => 200, // int
'statusText' => 'OK', // string
'headers' => [['content-type', 'text/plain'], ['x-custom', '1']],
'body' => '...response bytes...', // string
];
Če prenos sproži izjemo, Phasis jo ujame in pretvori:
Phasis\BuiltIn\Fetch\TransportExceptionz$e->kind === "aborted"→fetchzavrne zAbortError DOMException.kind === "timeout"→TypeError, ki vsebuje sporočilo.kind === "network-error"(privzeto) →TypeError.- Vse drugo →
TypeErrors sporočilom izjeme.
Primeri uporabe
Guzzle
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
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),
];
});
Zavračanje vsega
$engine->setFetchTransport(function () {
throw new \Phasis\BuiltIn\Fetch\TransportException(
'network access disabled in this sandbox',
'network-error',
);
});
To povzroči, da se vsak klic fetch() zavrne z TypeError. Uporabno za peskovnikovanje uporabniško podanega JS.
Lažni prenos za teste
$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'],
];
});
Kavelj pravilnika
Prenos izvede zahtevo; kavelj pravilnika odloči, ali naj se sploh izvede. Uporabite ga za uveljavljanje pravil samo za HTTPS, dodajanje glav, prepisovanje URL, sezname dovoljenih ali vezavo poverilnic za posameznega najemnika.
public function setFetchPolicy(callable $hook): void
Podpis kavlja: function (JsObject $request): ?JsObject. Če vrne null, se zahteva dovoli brez sprememb. Če vrne Request, se zahteva prepiše. Sprožena izjema zavrne fetch z navedeno napako.
$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;
});
Kavelj pravilnika se izvede pred prenosom — zato ga ne more zaobiti niti napačno delujoč ali nezaupanja vreden prenos.
Povzetek privzetega vedenja
| Zadeva | Privzeto |
|---|---|
| Prenos | CurlTransport (PHP ext-curl) |
| Preusmeritve | Po specifikaciji sledi največ 20 preusmeritvam. redirect: "manual" vrne odgovor preusmeritve z type: "opaqueredirect". |
| Časovna omejitev | 30 s po stenski uri, 10 s za povezavo |
| Preverjanje TLS | CURLOPT_SSL_VERIFYPEER = true (izklop ni mogoč — preglasite z zamenjavo prenosa) |
| User-Agent | Phasis/0.1 se doda samo, če še ni nastavljen |
| Piškotki | Nič se ne shrani. Omogočite jih z setCookieJar(). |
| Kavelj pravilnika | Brez. Vse zahteve so dovoljene, razen če jih izrecno zavrnete. |
| AbortSignal | Upošteva se med prenosom s preverjanjem povratnega klica napredka curl. |
Glejte tudi
- API referenca — kavlji Fetch — kratek pregled podpisov.
- Spletni API-ji — celoten nabor Fetch Pack.
- Shramba piškotkov — ohranjanje piškotkov med klici fetch z objektom shrambe PHP ali JS.