رسیدگی به خطا
معرفی
هنگامی که یک پروژه جدید لاراول را شروع می کنید، مدیریت خطا و استثنا از قبل برای شما پیکربندی شده است. با این حال، در هر زمانی، می توانید از
withExceptions
روش موجود در برنامه خود
bootstrap/app.php
برای مدیریت نحوه گزارش و ارائه استثناها توسط برنامه خود استفاده کنید.
شی
$exceptions
ارائه شده به
withExceptions
بسته شدن نمونه ای از
Illuminate\Foundation\Configuration\Exceptions
و مسئول مدیریت رسیدگی به استثنا در برنامه شما است. ما در طول این مستندات عمیقتر به این شی خواهیم پرداخت.
پیکربندی
گزینه
debug
موجود در
config/app.php
فایل پیکربندی شما تعیین می کند که واقعاً چه مقدار اطلاعات در مورد یک خطا به کاربر نمایش داده می شود. به طور پیش فرض، این گزینه به گونه ای تنظیم شده است که به مقدار
APP_DEBUG
متغیر محیطی که در فایل شما ذخیره می شود، احترام بگذارد
.env
.
در طول توسعه محلی، باید
APP_DEBUG
متغیر محیطی را روی
true
.
در محیط تولید شما، این مقدار باید همیشه باشد
false
. اگر مقدار
true
در مرحله تولید تنظیم شده باشد، در معرض خطر قرار دادن مقادیر حساس پیکربندی برای کاربران نهایی برنامه خود هستید.
رسیدگی به استثناها
استثناهای گزارشگری
در لاراول، گزارش استثنا برای ثبت استثناها یا ارسال آنها به یک سرویس خارجی Sentry یا Flare استفاده می شود . به طور پیش فرض، استثناها بر اساس پیکربندی ورود به سیستم شما ثبت می شوند . با این حال، شما آزاد هستید که استثناها را هر طور که می خواهید ثبت کنید.
اگر نیاز به گزارش انواع مختلف استثناها به روش های مختلف دارید، می توانید از
report
روش استثنا در برنامه خود
bootstrap/app.php
برای ثبت بسته شدن استفاده کنید که باید در زمانی که استثنایی از یک نوع معین باید گزارش شود اجرا شود. لاراول با بررسی نوع اشاره بسته مشخص می کند که بسته شدن چه نوع استثنایی را گزارش می کند:
->withExceptions(function (Exceptions $exceptions) { $exceptions->report(function (InvalidOrderException $e) { // ... });})
هنگامی که با استفاده از این متد، یک استثنای سفارشی را ثبت میکنید
report
، لاراول همچنان استثنا را با استفاده از پیکربندی پیشفرض گزارشگیری برای برنامه ثبت میکند. اگر میخواهید انتشار استثنا در پشته گزارش پیشفرض را متوقف کنید، میتوانید
stop
هنگام تعریف پاسخ به تماس گزارشی خود یا بازگشت
false
از پاسخ به تماس از این روش استفاده کنید:
->withExceptions(function (Exceptions $exceptions) { $exceptions->report(function (InvalidOrderException $e) { // ... })->stop(); $exceptions->report(function (InvalidOrderException $e) { return false; });})
برای سفارشی کردن گزارش استثنا برای یک استثنا خاص، میتوانید از استثناهای قابل گزارش نیز استفاده کنید .
زمینه ثبت جهانی
اگر در دسترس باشد، لاراول به طور خودکار شناسه کاربر فعلی را به عنوان داده های متنی به پیام گزارش هر استثنا اضافه می کند. شما می توانید داده های متنی جهانی خود را با استفاده از
context
روش استثنا در فایل برنامه خود تعریف کنید
bootstrap/app.php
. این اطلاعات در هر پیام گزارش استثنایی که توسط برنامه شما نوشته شده است گنجانده می شود:
->withExceptions(function (Exceptions $exceptions) { $exceptions->context(fn () => [ 'foo' => 'bar', ]);})
متن گزارش استثنا
در حالی که افزودن زمینه به هر پیام گزارش می تواند مفید باشد، گاهی اوقات یک استثنا خاص ممکن است زمینه منحصر به فردی داشته باشد که شما بخواهید آن را در گزارش های خود بگنجانید. با تعریف
context
روشی در یکی از استثناهای برنامه خود، میتوانید هر داده مرتبط با آن استثنا را که باید به ورودی گزارش استثنا اضافه شود، مشخص کنید:
<?php namespace App\Exceptions; use Exception; class InvalidOrderException extends Exception{ // ... /** * Get the exception's context information. * * @return array<string, mixed> */ public function context(): array { return ['order_id' => $this->orderId]; }}
یاور
report
گاهی اوقات ممکن است لازم باشد یک استثنا را گزارش کنید اما به رسیدگی به درخواست فعلی ادامه دهید. تابع
report
helper به شما امکان می دهد تا به سرعت یک استثنا را بدون ارائه صفحه خطا به کاربر گزارش دهید:
public function isValid(string $value): bool{ try { // Validate the value... } catch (Throwable $e) { report($e); return false; }}
کپی برداری از استثناهای گزارش شده
اگر از این تابع در سراسر برنامه خود استفاده می کنید
report
، ممکن است گهگاه یک استثنا را چندین بار گزارش دهید و ورودی های تکراری در گزارش های خود ایجاد کنید.
اگر میخواهید مطمئن شوید که یک نمونه از یک استثنا فقط یک بار گزارش میشود، میتوانید از روش استثنا در
فایل
dontReportDuplicates
برنامه خود استفاده کنید:
bootstrap/app.php
->withExceptions(function (Exceptions $exceptions) { $exceptions->dontReportDuplicates();})
اکنون، وقتی
report
کمک کننده با همان نمونه استثنا فراخوانی می شود، فقط اولین تماس گزارش می شود:
$original = new RuntimeException('Whoops!'); report($original); // reported try { throw $original;} catch (Throwable $caught) { report($caught); // ignored} report($original); // ignoredreport($caught); // ignored
سطوح ثبت استثنا
وقتی پیامها در گزارشهای برنامه شما نوشته میشوند ، پیامها در سطح گزارش مشخصی نوشته میشوند ، که نشاندهنده شدت یا اهمیت پیام ثبتشده است.
همانطور که در بالا ذکر شد، حتی زمانی که با استفاده از این روش، یک استثنا سفارشی را ثبت میکنید
report
، لاراول همچنان استثنا را با استفاده از پیکربندی پیشفرض گزارشگیری برای برنامه ثبت میکند. با این حال، از آنجایی که سطح گزارش گاهی اوقات میتواند بر کانالهایی که یک پیام در آنها ثبت میشود تأثیر بگذارد، ممکن است بخواهید سطح گزارشی را پیکربندی کنید که استثناهای خاصی در آن ثبت شوند.
برای انجام این کار، می توانید از
level
روش استثنا در فایل برنامه خود استفاده کنید
bootstrap/app.php
. این متد نوع استثنا را به عنوان اولین آرگومان و سطح log را به عنوان آرگومان دوم دریافت می کند:
use PDOException;use Psr\Log\LogLevel; ->withExceptions(function (Exceptions $exceptions) { $exceptions->level(PDOException::class, LogLevel::CRITICAL);})
نادیده گرفتن استثناها بر اساس نوع
هنگام ساخت برنامه خود، انواع استثناهایی وجود دارد که هرگز نمی خواهید گزارش دهید. برای نادیده گرفتن این استثناها، می توانید از
dontReport
روش استثنا در فایل برنامه خود استفاده کنید
bootstrap/app.php
. هر کلاس ارائه شده به این روش هرگز گزارش نخواهد شد. با این حال، ممکن است هنوز منطق رندر سفارشی داشته باشند:
use App\Exceptions\InvalidOrderException; ->withExceptions(function (Exceptions $exceptions) { $exceptions->dontReport([ InvalidOrderException::class, ]);})
در داخل، لاراول در حال حاضر برخی از انواع خطاها را برای شما نادیده می گیرد، مانند استثناهای ناشی از خطاهای 404 HTTP یا 419 پاسخ HTTP تولید شده توسط توکن های نامعتبر CSRF. اگر می خواهید به لاراول دستور دهید تا از نادیده گرفتن یک نوع استثنای خاص خودداری کند، می توانید از
stopIgnoring
روش استثنا در فایل برنامه خود استفاده کنید
bootstrap/app.php
:
use Symfony\Component\HttpKernel\Exception\HttpException; ->withExceptions(function (Exceptions $exceptions) { $exceptions->stopIgnoring(HttpException::class);})
رندر استثناها
به طور پیش فرض، کنترل کننده استثنا لاراول استثناها را به یک پاسخ HTTP برای شما تبدیل می کند. با این حال، شما آزاد هستید که یک بسته رندر سفارشی را برای استثناهایی از یک نوع مشخص ثبت کنید. شما می توانید این کار را با استفاده از
render
روش استثنا در فایل برنامه خود انجام دهید
bootstrap/app.php
.
بسته شدن ارسال شده به
render
متد باید یک نمونه از را برگرداند
Illuminate\Http\Response
که ممکن است از طریق
response
کمک کننده ایجاد شود. لاراول با بررسی نوع اشاره بسته تعیین می کند که بسته شدن چه نوع استثنایی را ارائه می دهد:
use App\Exceptions\InvalidOrderException;use Illuminate\Http\Request; ->withExceptions(function (Exceptions $exceptions) { $exceptions->render(function (InvalidOrderException $e, Request $request) { return response()->view('errors.invalid-order', [], 500); });})
همچنین می توانید از این
render
روش برای نادیده گرفتن رفتار رندر برای استثناهای داخلی لاراول یا سیمفونی مانند
NotFoundHttpException
. اگر بسته شدن داده شده به
render
متد مقداری را برنگرداند، از رندر استثنایی پیشفرض لاراول استفاده میشود:
use Illuminate\Http\Request;use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; ->withExceptions(function (Exceptions $exceptions) { $exceptions->render(function (NotFoundHttpException $e, Request $request) { if ($request->is('api/*')) { return response()->json([ 'message' => 'Record not found.' ], 404); } });})
ارائه استثناها به عنوان JSON
هنگام ارائه یک استثنا، لاراول به طور خودکار تعیین می کند که آیا استثنا باید به عنوان یک پاسخ HTML یا JSON بر اساس هدر
Accept
درخواست ارائه شود. اگر میخواهید نحوه تعیین پاسخهای استثنایی HTML یا JSON را توسط لاراول سفارشی کنید، میتوانید از
shouldRenderJsonWhen
روش زیر استفاده کنید:
use Illuminate\Http\Request;use Throwable; ->withExceptions(function (Exceptions $exceptions) { $exceptions->shouldRenderJsonWhen(function (Request $request, Throwable $e) { if ($request->is('admin/*')) { return true; } return $request->expectsJson(); });})
سفارشی کردن پاسخ استثنا
به ندرت، ممکن است لازم باشد کل پاسخ HTTP ارائه شده توسط کنترل کننده استثنای لاراول را سفارشی کنید. برای انجام این کار، می توانید یک بسته سفارشی سازی پاسخ را با استفاده از
respond
روش ثبت کنید:
use Symfony\Component\HttpFoundation\Response; ->withExceptions(function (Exceptions $exceptions) { $exceptions->respond(function (Response $response) { if ($response->getStatusCode() === 419) { return back()->with([ 'message' => 'The page expired, please try again.', ]); } return $response; });})
استثناهای گزارش پذیر و قابل اجرا
به جای تعریف گزارشدهی سفارشی و رفتار رندر در فایل برنامهتان
bootstrap/app.php
، میتوانید
مستقیماً استثناهای برنامه خود را تعریف کنید
report
و روشهایی را تعیین کنید.
render
هنگامی که این متدها وجود داشته باشند، به طور خودکار توسط فریمورک فراخوانی می شوند:
<?php namespace App\Exceptions; use Exception;use Illuminate\Http\Request;use Illuminate\Http\Response; class InvalidOrderException extends Exception{ /** * Report the exception. */ public function report(): void { // ... } /** * Render the exception into an HTTP response. */ public function render(Request $request): Response { return response(/* ... */); }}
اگر استثنای شما استثنایی را گسترش دهد که از قبل قابل اجرا است، مانند یک استثنای داخلی لاراول یا Symfony، میتوانید
false
از متد استثنا
render
برای ارائه پاسخ HTTP پیشفرض استثنا برگردید:
/** * Render the exception into an HTTP response. */public function render(Request $request): Response|bool{ if (/** Determine if the exception needs custom rendering */) { return response(/* ... */); } return false;}
اگر استثنای شما حاوی منطق گزارش دهی سفارشی است که فقط زمانی لازم است که شرایط خاصی برآورده شود، ممکن است لازم باشد به لاراول دستور دهید که گاهی استثنا را با استفاده از پیکربندی پیش فرض مدیریت استثنا گزارش دهد. برای انجام این کار، می توانید
false
از روش استثنا برگردید
report
:
/** * Report the exception. */public function report(): bool{ if (/** Determine if the exception needs custom reporting */) { // ... return true; } return false;}
میتوانید وابستگیهای مورد نیاز متد را تایپ کنید و آنها به طور خودکار توسط کانتینر سرویس
report
لاراول به متد تزریق میشوند .
کاهش استثناهای گزارش شده
اگر برنامه شما تعداد بسیار زیادی استثنا را گزارش می دهد، ممکن است بخواهید تعداد استثناهایی که واقعاً ثبت شده یا به سرویس ردیابی خطای خارجی برنامه شما ارسال شده اند را تعیین کنید.
برای گرفتن نرخ نمونه تصادفی از استثناها، می توانید از
throttle
روش استثنا در فایل برنامه خود استفاده کنید
bootstrap/app.php
. متد
throttle
یک بسته را دریافت می کند که باید یک نمونه را برگرداند
Lottery
:
use Illuminate\Support\Lottery;use Throwable; ->withExceptions(function (Exceptions $exceptions) { $exceptions->throttle(function (Throwable Throwable) { return Lottery::odds(1, 1000); });})
همچنین امکان نمونه گیری مشروط بر اساس نوع استثنا وجود دارد. اگر میخواهید فقط نمونههایی از یک کلاس استثنای خاص را نمونهگیری کنید، میتوانید یک
Lottery
نمونه را فقط برای آن کلاس برگردانید:
use App\Exceptions\ApiMonitoringException;use Illuminate\Support\Lottery;use Throwable; ->withExceptions(function (Exceptions $exceptions) { $exceptions->throttle(function (Throwable Throwable) { if ($e instanceof ApiMonitoringException) { return Lottery::odds(1, 1000); } });})
همچنین میتوانید استثناهای محدود ثبت شده یا ارسال شده به یک سرویس ردیابی خطای خارجی را با بازگرداندن یک
Limit
نمونه به جای یک رتبهبندی کنید
Lottery
. اگر میخواهید در برابر هجوم ناگهانی استثناها که لاگهایتان را سرازیر میکنند، محافظت کنید، به عنوان مثال، هنگامی که یک سرویس شخص ثالث مورد استفاده برنامه شما قطع است، مفید است:
use Illuminate\Broadcasting\BroadcastException;use Illuminate\Cache\RateLimiting\Limit;use Throwable; ->withExceptions(function (Exceptions $exceptions) { $exceptions->throttle(function (Throwable Throwable) { if ($e instanceof BroadcastException) { return Limit::perMinute(300); } });})
به طور پیشفرض، محدودیتها از کلاس استثنا به عنوان کلید محدودیت نرخ استفاده میکنند. شما می توانید این را با تعیین کلید خود با استفاده از
by
روش زیر سفارشی کنید
Limit
:
use Illuminate\Broadcasting\BroadcastException;use Illuminate\Cache\RateLimiting\Limit;use Throwable; ->withExceptions(function (Exceptions $exceptions) { $exceptions->throttle(function (Throwable Throwable) { if ($e instanceof BroadcastException) { return Limit::perMinute(300)->by($e->getMessage()); } });})
البته، میتوانید ترکیبی از
Lottery
و
Limit
نمونهها را برای استثناهای مختلف برگردانید:
use App\Exceptions\ApiMonitoringException;use Illuminate\Broadcasting\BroadcastException;use Illuminate\Cache\RateLimiting\Limit;use Illuminate\Support\Lottery;use Throwable; ->withExceptions(function (Exceptions $exceptions) { $exceptions->throttle(function (Throwable Throwable) { return match (true) { $e instanceof BroadcastException => Limit::perMinute(300), $e instanceof ApiMonitoringException => Lottery::odds(1, 1000), default => Limit::none(), }; });})
استثناهای HTTP
برخی استثناها کدهای خطای HTTP را از سرور توصیف می کنند. به عنوان مثال، این ممکن است یک خطای «صفحه یافت نشد» (404)، یک «خطای غیرمجاز» (401)، یا حتی یک خطای 500 توسط برنامهنویس باشد. برای ایجاد چنین پاسخی از هر نقطه در برنامه خود، می توانید از
abort
راهنما استفاده کنید:
abort(404);
صفحات خطای سفارشی HTTP
لاراول نمایش صفحات خطای سفارشی برای کدهای وضعیت HTTP مختلف را آسان می کند. به عنوان مثال، برای سفارشی کردن صفحه خطا برای کدهای وضعیت HTTP 404، یک
resources/views/errors/404.blade.php
قالب نمایش ایجاد کنید. این نمای برای تمام خطاهای 404 ایجاد شده توسط برنامه شما ارائه می شود. نماهای موجود در این فهرست باید به گونه ای نامگذاری شوند که با کد وضعیت HTTP مطابقت دارند. نمونه
ای
Symfony\Component\HttpKernel\Exception\HttpException
که توسط
abort
تابع مطرح می شود به عنوان یک متغیر به view ارسال می شود
$exception
:
<h2>{{ $exception->getMessage() }}</h2>
شما می توانید قالب های صفحه خطای پیش فرض لاراول را با استفاده از
vendor:publish
دستور Artisan منتشر کنید. پس از انتشار قالب ها، می توانید آنها را به دلخواه شخصی سازی کنید:
php artisan vendor:publish --tag=laravel-errors
صفحات خطای بازگشتی HTTP
همچنین میتوانید برای یک سری کدهای وضعیت HTTP یک صفحه خطای «بازگشت» تعریف کنید. اگر صفحه مربوط به کد وضعیت HTTP خاصی که رخ داده وجود نداشته باشد، این صفحه نمایش داده می شود. برای انجام این کار، یک
4xx.blade.php
الگو و یک
5xx.blade.php
الگو را در فهرست برنامه خود تعریف کنید
resources/views/errors
.