HTTP istemcileri
Varsayılan olarak cURL, kendi istemcinizi kullanmayı tercih ettiğinizde herhangi bir PSR-18 istemcisi ve testler için sahte bir istemci.
Varsayılan
httpClient: verilmediğinde istekler, curl eklentisinden başka hiçbir şeye ihtiyaç duymayan OpenEmail\Http\CurlHttpClient üzerinden geçer. İstemci başına tek bir cURL tanıtıcısı tutar; bu yüzden ikinci bir istek, ilkinin açtığı bağlantıyı yeniden kullanır. Proxy'ler, sertifika yetkilileri ve ek cURL ayarları için seçeneklerini Yapılandırma sayfası listeler.
Baytları ne taşırsa taşısın, geri kalan her şeyi istemcinin kendisi yapar: kimlik bilgisi, idempotency anahtarları, yeniden denemeler ve geri çekilmeleri, her denemenin zaman aşımı ve her başarısızlığın istisnası. Bir HTTP istemcisi yalnızca tek bir istek gönderir ve yanıtı geri verir.
Herhangi bir PSR-18 istemcisi
OpenEmail\Http\Psr18HttpClient, Guzzle ya da Symfony HttpClient gibi PSR-18'i uygulayan herhangi bir istemciyi sarar; böylece istekler, uygulamanızın zaten yapılandırdığı istemciden, onun middleware, günlükleme ve proxy ayarlarıyla birlikte geçer.
use GuzzleHttp\Client;use OpenEmail\Http\Psr18HttpClient;use OpenEmail\OpenEmail; $client = new OpenEmail(httpClient: new Psr18HttpClient(new Client())); $client->me->ping();use OpenEmail\Http\Psr18HttpClient;use OpenEmail\OpenEmail;use Symfony\Component\HttpClient\HttpClient;use Symfony\Component\HttpClient\Psr18Client; $http = new Psr18Client(HttpClient::create(['timeout' => 30, 'max_redirects' => 0])); $client = new OpenEmail(httpClient: new Psr18HttpClient($http)); $client->me->ping();PSR-18 isteklerini PSR-17 fabrikalarıyla oluşturur. Adaptör, Symfony'nin Psr18Client sınıfı gibi istemcinin kendisi de bir fabrikaysa onu, ardından kuruluysa php-http/discovery paketini, ardından nyholm/psr7 ya da Guzzle'ın kendi fabrikalarını kullanır; hiçbirini bulamazsa neyin kurulacağını belirten bir InvalidArgumentException fırlatır. Bunları kendiniz seçmek için requestFactory: ve streamFactory: geçirin. Symfony'nin Psr18Client sınıfı ayrıca PSR-18 arayüzlerine ve bir PSR-17 uygulamasına ihtiyaç duyar; bu yüzden onu composer require symfony/http-client psr/http-client nyholm/psr7 ile kurun.
use GuzzleHttp\Client;use Nyholm\Psr7\Factory\Psr17Factory;use OpenEmail\Http\Psr18HttpClient;use OpenEmail\OpenEmail; $factory = new Psr17Factory(); $client = new OpenEmail(httpClient: new Psr18HttpClient(new Client(), requestFactory: $factory, streamFactory: $factory)); $client->me->ping();| Konu | Ne olur |
|---|---|
| Zaman aşımları | Guzzle, istemcinin timeout: değerini her istekte alır. PSR-18'in başka herhangi bir istemciye zaman aşımı geçirmenin bir yolu yoktur; bu yüzden yukarıdaki HttpClient::create(['timeout' => 30, 'max_redirects' => 0]) örneğinde olduğu gibi sardığınız istemcide bir zaman aşımı ayarlayın, yoksa hiç yanıt gelmeyen bir istek sonsuza dek bekleyebilir. |
| Hata durumları | Bir PSR-18 istemcisi 4xx ve 5xx yanıtlarında istisna fırlatmak yerine yanıtı döndürür ve adaptör Guzzle'a da aynısını yapmasını söyler; böylece her ret yine doğru ApiException hâline gelir. |
| Yanıt yok | Sarılan istemciden gelen bir ClientExceptionInterface, iletisini koruyan bir NetworkException hâline gelir, ama istisnanın kendisi tutulmaz, çünkü o istisna isteği ve Authorization başlığını taşır. İleti isteğin zaman aşımına uğradığını söylüyorsa isTimeout() true olur ve Guzzle dışındaki her istemcide ileti, zaman aşımının sarılan istemcinin kendi zaman aşımı olduğunu söyler. |
| Yönlendirmeler | Guzzle'a onları izlememesi söylenir ve Symfony örneği max_redirects değerini 0 yapar; bu yüzden bir yönlendirme, varsayılan cURL istemcisinde olduğu gibi bir ApiException olur. |
Kendi istemciniz
httpClient:, tek metodu olan bir arayüz olan OpenEmail\Http\HttpClient arayüzünü uygulayan her şeyi kabul eder: send(HttpRequest $request): HttpResponse. 4xx ve 5xx dahil her durum için yanıtı döndürün ve yalnızca hiç yanıt gelmediğinde istisna fırlatın.
| Sınıf | Ne taşır |
|---|---|
| HttpRequest | method, url, ad ve değerlerden oluşan bir dizi olarak headers, dize ya da null olarak body ve saniye cinsinden ya da hiç yoksa null olarak timeout. header($name) bir başlığı büyük/küçük harfe bakmadan okur. var_dump(), print_r() ve json_encode(), Authorization başlığını [redacted] olarak gösterir, ama var_export() ve Symfony'nin dump() işlevi headers değerini olduğu gibi yazdırır; bu yüzden bir isteği asla bu ikisiyle günlüğe yazmayın. |
| HttpResponse | new HttpResponse($status, $headers, $body) olarak oluşturulur. Başlık adlarını küçük harfe çevirir ve header($name) bir başlığı büyük/küçük harfe bakmadan okur. |
| HttpClientException | Hiç yanıt gelmediğinde onu send içinden fırlatın. new HttpClientException($message, timeout: true) bir zaman aşımını işaretler. |
Ağ olmadan test etme
Sahte bir istemci dışarı gidecek olanı kaydeder ve testin ihtiyaç duyduğu yanıtı verir; böylece hiçbir şey makineden çıkmaz ve test tam olarak neyin gönderildiğini denetleyebilir.
use OpenEmail\Http\HttpClient;use OpenEmail\Http\HttpRequest;use OpenEmail\Http\HttpResponse;use OpenEmail\OpenEmail; $fake = new class implements HttpClient { public array $requests = []; public function send(HttpRequest $request): HttpResponse { $this->requests[] = $request; return new HttpResponse( 200, ['content-type' => 'application/json'], json_encode(['id' => 'msg_test', 'status' => 'sent', 'replayed' => false], JSON_THROW_ON_ERROR), ); }}; $testClient = new OpenEmail(apiKey: 'oe_test_fake', httpClient: $fake, maxRetries: 0, disableUpdateNotice: true); $sent = $testClient->emails->send([ 'from' => '[email protected]', 'to' => '[email protected]', 'subject' => 'Hi', 'text' => 'Hello',]); $request = $fake->requests[0]; echo $sent['status'], ' ', $request->method, ' ', $request->url, ' ', $request->header('Idempotency-Key'), PHP_EOL;var_dump($request);- Eşleşen
ApiExceptionalt sınıfını elde etmek için gövde olarak API'nin hata zarfını içeren, 2xx dışında bir durum döndürün; örneğin{"error": {"type": "validation_error", "code": "invalid_parameter", "message": "..."}}. isTimeout()değeri true olan birNetworkExceptionelde etmek içinsendiçindennew HttpClientException('timed out', timeout: true)fırlatın.RuntimeExceptiongibi başka herhangi birException,isTimeout()değeri false olan birNetworkExceptionhâline gelir.- Bir
LogicExceptionveTypeErrorgibi herhangi birError, sahte istemcideki hatalar sayılır. Değiştirilmeden fırlatılırlar ve asla yeniden denenmezler.
Hataları senaryolaştırırken test istemcisini maxRetries: 0 ile kurun. Aksi hâlde tekrarlanması güvenli bir çağrıda yeniden denenebilir bir durum ya da bir ağ hatası, aralarında gerçek beklemelerle üç kez denenir.