مرا اسکن کن!

استفاده از HTTP Client در لاراول

استفاده از HTTP Client در لاراول



خیلی وقتا فعالیت برنامه ما وابسته به یک برنامه دیگه هست . ما توی قسمت Frontend برای ارتباط با یک سرور دیگه از ای‌جکس استفاده می‌کنیم . اما توی قسمت Backend اگه به اطلاعاتی از یک سرور دیگه لازم داشته باشیم ، چطوری می‌تونیم درخواست ارسال کنیم و پاسخ بگیریم ؟ شاید قبلاً از cURL یا Guzzle استفاده می‌کردیم . اما همیشه راه راحت‌تری وجود داره ! اگه از فریم‌ورک لاراول استفاده می‌کنیم ، می‌تونیم این کار رو با یک ابزار ساده ، سریع و در حین حال قدرتمند به اسم HTTP Client انجام بدیم .

 

HTTP Client چیه ؟

HTTP Client لاراول ابزاری هست که برای ارسال درخواست‌های HTTP و تعامل با سرویس‌های تحت وب استفاده میشه . HTTP Client پشت پرده از پکیج گازِل (Guzzle) استفاده می‌کنه و برای این معرفی شده تا کار با اون رو ساده‌تر و سریع‌تر کنه . به قول معروف ، یک Wrapper هست برای گازِل .

با HTTP Client ، بدون پیچیدگی‌هایی که گازل داره ، می‌تونیم درخواست‌های HTTP به یک سرور دیگه بفرستیم :

Http::get('http://test.com');

توی ادامه این ابزار رو بررسی می‌کنیم و با نکات کاربردی اون آشنا می‌شیم 

چون این ابزار از Guzzle استفاده می‌کنه ، قبل از شروع باید از نصب اون مطمئن بشیم . توی یک برنامه لاراولی، Guzzle بطور پیشفرض اضافه شده . هر چند می‌تونیم اون رو با دستور کامپوزر زیر نصب کنیم :

composer require guzzlehttp/guzzle

یک درخواست بسازیم

ساختن یک درخواست با HTTP Client به سادگی کد زیر هست . برای ساختن یک درخواست GET ، از متد get کلاس Http استفاده می‌کنیم :

use Illuminate\Support\Facades\Http;

$response = Http::get('http://test.com');

برای ارسال درخواست‌های POST و ... متدهایی با همین اسم وجود داره :

Http::post('http://www.test.com');
Http::delete('http://www.test.com');
Http::head('http://www.test.com');
Http::patch('http://www.test.com');
Http::put('http://www.test.com');

خروجی این متدها ، یک نمونه از کلاس Illuminate\Http\Client\Response هست که شامل متدهای متنوع زیر میشه که تو ادامه اونها رو بررسی می‌کنیم :

$response->body() : string;
$response->json() : array|mixed;
$response->status() : int;
$response->ok() : bool;
$response->successful() : bool;
$response->failed() : bool;
$response->serverError() : bool;
$response->clientError() : bool;
$response->header($header) : string;
$response->headers() : array;

نتیجه درخواست ؟

با استفاده از متد status() می‌تونیم کد HTTP نتیجه درخواست رو متوجه بشیم :

$response = Http::get('http://www.example.com');

echo $response->status(); // 200, 301, 404, 500, ...

این متد اهمیت زیادی داره چون بیشتر متدهای کلاس Response از این متد استفاده می‌کنن که با اونها آشنا می‌شیم .

آیا درخواست موفقیت آمیز بود ؟

با متد successful() می‌تونیم بررسی کنیم که آیا درخواست ما موفقیت آمیز بود یا خیر :

$response = Http::get('http://test.com');

if ($response->successful()) {
    // do something
}

ببینیم متد successful() پشت پرده دقیقاً چه کاری انجام میده :

public function successful()
{
    return $this->status() >= 200 && $this->status() < 300;
}

همونطور که می‌بینیم این متد بررسی می‌کنه که آیا status() بین ۲۰۰ و ۳۰۰ هست یا خیر .

اگه بخوایم بررسی کنیم که آیا کد نتیجه درخواست دقیقاً برابر با ۲۰۰ هست ، از متد ok() استفاده می‌کنیم :

$response = Http::get('http://test.com');

if ($response->ok()) {
    // The HTTP status code is 200
}

درخواست با خطا مواجه شد ؟

برای اینکه بررسی کنیم آیا درخواست ما با خطا مواجه شده ، از متد failed() استفاده می‌کنیم :

$response = Http::get('http://test.com/failing-url');

if ($response->failed()) {
    // Request failed
}

این متد جزییات زیادی رو در اختیار ما نمی‌گذاره . خوبه با کاری که این متد انجام میده هم آشنا بشیم . متد failed() خودش از دو تا متد دیگه استفاده می‌کنه :

public function failed()
{
    return $this->serverError() || $this->clientError();
}

البته از این متدها می‌تونیم بصورت جدا هم استفاده کنیم .

همونطور که می‌دونیم اگه خطا از سمت سرور باشه ، کد HTTP از عدد ۵۰۰ شروع میشه . متد serverError() هم دقیقاً همین رو بررسی می‌کنه :

public function serverError()
{
    return $this->status() >= 500;
}

و همچنین اگه خطا به درخواست کاربر ارتباط داشته باشه ، کد HTTP از ۴۰۰ تا ۵۰۰ خواهد بود که متد clientError() همین رو بررسی می‌کنه :

public function clientError()
{
    return $this->status() >= 400 && $this->status() < 500;
}

اطلاعات پاس بدیم

از آرگومان دوم می‌تونیم برای پاس دادن اطلاعات اضافی استفاده کنیم :

$response = Http::post('http://test.com/posts', [
    'title' => 'New post',
    'status' => 'Draft',
]);

اگه درخواست بصورت GET باشه ، اطلاعات بصورت Query Parameter ارسال میشه :

$response = Http::get('http://test.com/posts', [
    'id' => '29',
    'sort' => 'ASC',
]);

// http://test.com/posts?id=29&sort=ASC

در حالت پیشفرض ، همه اطلاعات با هدر Content-Type با مقدار  application/json فرستاده میشه . اما تو درخواست POST اگه بخوایم اطلاعات رو مثل یک فرم بفرستیم ، از متد asForm() بصورت زیر استفاده می‌کنیم :

$response = Http::asForm()->post('http://test.com/posts', [
    'title' => 'New post',
    'status' => 'Draft',
]);

با این کار ، مقدار هدر Content-Type به application/x-www-form-urlencoded تغییر پیدا می‌کنه . اما با این هدر نمی‌تونیم فایل ارسال کنیم . برای ارسال و ضمیمه کردن فایل به درخواست ، از متد attach() استفاده می‌کنیم :

$response = Http::attach(
  'image', file_get_contents('cat.jpg'), 'photo.jpg'
)->post('http://test.com/posts');

توی مثال بالا ، آرگومان اول متد attach() اسم پارامتری هست که پاس می‌دیم . آرگومان دوم محتویات فایل هست . آرگومان سوم اختیاری هست و مقدار اون در نظر گرفته میشه برای اسم فایل .

برای ضمیمه کردن چند فایل باید چند بار از متد attach() استفاده کنیم . اما راه راحت‌تر اینه که این کار رو با یک متد انجام بدیم .

پس اگه چند تا فایل داریم می‌تونیم از متد attachMany() استفاده کنیم :

$response = Http::attachMany(
    ['image1', file_get_contents('cat1.jpg'), 'photo1.jpg'],
    ['image2', file_get_contents('cat2.jpg'), 'photo2.jpg'],
    ['image3', file_get_contents('cat3.jpg'), 'photo3.jpg'],
)->post('http://test.com/posts');

این ویژگی از لاراول ورژن ۸ در دسترس هست .

 

ارسال Header

با استفاده از متد withHeaders() می‌تونیم به درخواست، هدر ضمیمه کنیم :

$response = Http::withHeaders([
    'Accept' => 'application/json',
    'X-Custom' => 'Meow'
])->post('http://test.com/posts');

احراز هویت

اگه درخواست برای بررسی شدن ، نیاز به احراز هویت از نوع Basic یا Digest داره می‌تونیم از متدهای withBasicAuth() یا withDigestAuth() استفاده کنیم :

$response = Http::withBasicAuth('username', 'psswrd')->post(...);

// Digest authentication...
$response = Http::withDigestAuth('username', 'psswrd')->post(...);

و اگه نیاز به تنظیم کردن هدر Authorization داریم ، می‌تونیم بطور مستقیم از متد withToken() استفاده کنیم :

$response = Http::withToken('token')->post(...);

این متد دو تا پارامتر می‌گیره . پارامتر اول توکن و پارامتر دوم نوع توکن هست که بطور پیشفرض Bearer در نظر گرفته میشه .

 

چقدر صبر کنیم برای پاسخ ؟

با استفاده از متد timeout() می‌تونیم مشخص کنیم حداکثر چند ثانیه منتظر اومدن پاسخ باشیم :

$response = Http::timeout(3)->get(...);

اگه توی بازه زمانی مشخص شده پاسخی نیومد ، یک Exception از نوع Illuminate\Http\Client\ConnectionException خواهیم داشت .

 

دوباره تلاش کن

اگه درخواست با خطا مواجه شد ، این امکان وجود داره که بطور خودکار درخواست رو دوباره بفرستیم . برای این کار از متد retry() استفاده می‌کنیم . این متد ۲ آرگومان قبول می‌کنه . توی آرگومان اول می‌گیم چند بار تلاش کن و توی آرگومان دوم مشخص می‌کنیم که درخواست بعدی با چقدر تاخیر شروع بشه . این مقدار رو به میلی‌ثانیه مشخص می‌کنیم :

$response = Http::retry(3, 100)->get(...);

اگه همه درخواست‌ها با خطا مواجه بشه، یک Exception از نوع Illuminate\Http\Client\RequestException خواهیم داشت .

 

مدیریت خطاها

توی پکیج گازل ، خطاهای 4xx و 5xx باعث به وجود اومدن Exception میشد . اما توی HTTP Client این اتفاق نمی‌افته و همونطور که بررسی کردیم ، برای مدیریت این خطاها از متدهای زیر استفاده می‌کنیم :

$response->failed();
$response->clientError();
$response->serverError();

اما به هر صورت اگه می‌خوایم اون Exception رو داشته باشیم می‌تونیم از متد throw() بصورت زیر استفاده کنیم :

$response = Http::post(...);

// Throw an exception if a client or server error occurred...
$response->throw();

return $response->body();

می‌تونیم بصورت زیر خلاصه‌تر هم بنویسیم :

return Http::post(...)->throw()->body();

اگه هیچ خطایی نداشتیم، ادامه کد یعنی ->body(); اجرا میشه .

اگه خطایی رخ داد و می‌خوایم قبل از Throw شدنِ Exception یه سری کار انجام بدیم ، می‌تونیم اونها رو بصورت زیر توی متد throw() بنویسیم :

return Http::post(...)->throw(function ($response, $e) {
    // Do something here
})->body();

آپشن‌های گازل

چون HTTP Client پشت پرده از گازل استفاده می‌کنه ، می‌تونیم آپشن‌های مخصوص گازل رو با متد withOptions() تعریف کنیم :

$response = Http::withOptions([
    'debug' => true,
])->get('http://test.com');

تست برنامه

خیلی وقت‌ها می‌خوایم برنامه رو تست کنیم و لازم نیست درخواست واقعی زده بشه . مثلاً می‌خوایم مراحل بعد از درخواست رو بنویسیم و توسعه بدیم . اگه از متد fake() بصورت زیر استفاده کنیم ، درخواست واقعی اتفاق نمی‌افته و همچنین کد HTTP برای هر درخواست ۲۰۰ خواهد بود :

Http::fake();

$response = Http::post(...);

اگه می‌خوایم کد HTTP رو تغییر بدیم می‌تونیم از کد زیر استفاده کنیم :

Http::fake(function($request) {
    return Http::response(['message' => '...'], 400);
});

$response = Http::get('...');

if ($response->failed()) {
    // do something
}

اگه می‌خوایم فقط یک سری آدرس‌های خاص رو fake() کنیم ، اونها رو بصورت زیر تعریف می‌کنیم :

Http::fake([
    'github.com/*' => Http::response(['foo' => 'bar'], 200, ['Headers']),

    'google.com/*' => Http::response('Hello World', 200, ['Headers']),
]);

توی کد بالا تمام درخواست‌هایی که به سمت google.com و github.com بره fake میشن و واقعی نیستن .


نوشته شده توسط :

وحید صمدیان وحید صمدیان



شنبه, 23 مهر 1401

تعداد بازديد : 125

برچسب ها : فریم ورک لاراول

3.0 ستاره