Prologo
Primi Passi
Architettura
Le Basi
- Routing
- Middleware
- Protezione da CSRF
- Controller
- Richieste
- Risposte
- Views
- Blade
- Vite
- URL
- Sessioni
- Validazione
- Errori
- Logging
Approfondimenti
- Artisan
- Broadcasting
- Cache
- Collezioni
- Concorrenza
- Contesto
- Contratti
- Eventi
- File System
- Helpers
- Client HTTP
- Localizzazione
- Notifiche
- Sviluppo di Package
- Processi
- Code
- Rate-limiting
- Stringhe
- Scheduling di Task
Sicurezza
Database
Eloquent ORM
Testing
Package
Errori
Introduzione
Quando inizi un nuovo progetto Laravel, la gestione degli errori e delle eccezioni è già configurata per te; tuttavia, in qualsiasi momento, puoi utilizzare il metodo withExceptions
nel file bootstrap/app.php
della tua applicazione per gestire come le eccezioni vengono segnalate e visualizzate dalla tua applicazione.
L’oggetto $exceptions
fornito alla closure withExceptions
è un’istanza di Illuminate\Foundation\Configuration\Exceptions
ed è responsabile della gestione delle eccezioni nella tua applicazione. Approfondiremo questo oggetto durante tutta questa documentazione.
Configurazione
L’opzione debug
nel tuo file di configurazione config/app.php
determina quante informazioni su un errore vengono effettivamente mostrate all’utente. Per default, questa opzione è impostata per rispettare il valore della variabile di ambiente APP_DEBUG
, che si trova nel tuo file .env
.
Durante lo sviluppo locale, dovresti impostare la variabile di ambiente APP_DEBUG
su true
. Nell’ambiente di produzione, questo valore dovrebbe essere sempre false
. Se il valore è impostato su true
in produzione, rischi di esporre valori di configurazione sensibili agli utenti finali della tua applicazione.
Gestione delle Eccezioni
Reporting Exceptions
In Laravel, il reporting delle eccezioni viene utilizzato per registrare le eccezioni o inviarle a un servizio esterno come Sentry o Flare. Per impostazione predefinita, le eccezioni verranno registrate in base alla tua configurazione di logging. Tuttavia, sei libero di registrare le eccezioni come preferisci.
Se hai bisogno di gestire diversi tipi di eccezioni in modi differenti, puoi utilizzare il metodo report
nelle eccezioni della tua applicazione in bootstrap/app.php
per registrare una closure che verrà eseguita quando un’eccezione di un determinato tipo deve essere segnalata. Laravel determinerà il tipo di eccezione che la closure segnala esaminando l’hint di tipo della closure:
->withExceptions(function (Exceptions $exceptions) {
$exceptions->report(function (InvalidOrderException $e) {
// ...
});
})
Quando registri una callback personalizzata per il reporting delle eccezioni usando il metodo report
, Laravel registrerà comunque l’eccezione utilizzando la configurazione di logging predefinita per l’applicazione. Se desideri interrompere la propagazione dell’eccezione allo stack di logging predefinito, puoi utilizzare il metodo stop
quando definisci la tua callback di reporting oppure restituire false
dalla callback:
->withExceptions(function (Exceptions $exceptions) {
$exceptions->report(function (InvalidOrderException $e) {
// ...
})->stop();
$exceptions->report(function (InvalidOrderException $e) {
return false;
});
})
Per personalizzare il reporting delle eccezioni per una determinata eccezione, puoi anche utilizzare reportable exceptions.
Contesto Globale del Log
Se disponibile, Laravel aggiunge automaticamente l’ID dell’utente corrente a ogni messaggio di log delle eccezioni come dato contestuale. Puoi definire i tuoi dati contestuali globali utilizzando il metodo context
delle eccezioni nel file bootstrap/app.php
della tua applicazione. Queste informazioni saranno incluse in ogni messaggio di log delle eccezioni scritto dalla tua applicazione:
->withExceptions(function (Exceptions $exceptions) {
$exceptions->context(fn () => [
'foo' => 'bar',
]);
})
Contesto del Log delle Eccezioni
Aggiungere contesto a ogni messaggio di log può essere utile, ma a volte una particolare eccezione potrebbe avere un contesto unico che desideri includere nei tuoi log. Definendo un metodo context
in una delle eccezioni della tua applicazione, puoi specificare i dati rilevanti per quell’eccezione che dovrebbero essere aggiunti alla voce di log dell’eccezione:
<?php
namespace App\Exceptions;
use Exception;
class InvalidOrderException extends Exception
{
// ...
/**
* Ottiene le informazioni di contesto dell'eccezione.
*
* @return array<string, mixed>
*/
public function context(): array
{
return ['order_id' => $this->orderId];
}
}
L’helper report
A volte potresti dover segnalare un’eccezione ma continuare a gestire la richiesta corrente. La funzione helper report
ti permette di segnalare rapidamente un’eccezione senza mostrare una pagina di errore all’utente:
public function isValid(string $value): bool
{
try {
// Valida il valore...
} catch (Throwable $e) {
report($e);
return false;
}
}
Deduplicazione delle Eccezioni Segnalate
Se stai utilizzando la funzione report
in tutta la tua applicazione, potresti occasionalmente segnalare la stessa eccezione più volte, creando voci duplicate nei tuoi log.
Se desideri assicurarti che un’unica istanza di un’eccezione venga segnalata solo una volta, puoi chiamare il metodo dontReportDuplicates
nell’applicazione nel file bootstrap/app.php
:
->withExceptions(function (Exceptions $exceptions) {
$exceptions->dontReportDuplicates();
})
Ora, quando l’helper report
viene chiamato con la stessa istanza di un’eccezione, verrà segnalata solo la prima chiamata:
$original = new RuntimeException('Whoops!');
report($original); // segnalata
try {
throw $original;
} catch (Throwable $caught) {
report($caught); // ignorata
}
report($original); // ignorata
report($caught); // ignorata
Livelli di Log delle Eccezioni
Quando i messaggi vengono scritti nei log della tua applicazione, i messaggi sono registrati a un livello di log specificato, che indica la gravità o l’importanza del messaggio registrato.
Come menzionato sopra, anche quando registri una callback personalizzata per la segnalazione delle eccezioni usando il metodo report
, Laravel registrerà comunque l’eccezione utilizzando la configurazione di log predefinita per l’applicazione. Tuttavia, poiché il livello di log può influenzare i canali su cui viene registrato un messaggio, potresti voler configurare il livello di log a cui vengono registrate certe eccezioni.
Per fare questo, puoi usare il metodo level
per le eccezioni nel file bootstrap/app.php
della tua applicazione. Questo metodo riceve il tipo di eccezione come primo argomento e il livello di log come secondo argomento:
use PDOException;
use Psr\Log\LogLevel;
->withExceptions(function (Exceptions $exceptions) {
$exceptions->level(PDOException::class, LogLevel::CRITICAL);
})
Ignorare le Eccezioni per Tipo
Quando sviluppi la tua applicazione, ci saranno alcuni tipi di eccezioni che non vorrai mai segnalare. Per ignorare queste eccezioni, puoi utilizzare il metodo dontReport
nel file bootstrap/app.php
della tua applicazione. Qualsiasi classe fornita a questo metodo non sarà mai segnalata; tuttavia, potrebbero comunque avere una logica di rendering personalizzata:
use App\Exceptions\InvalidOrderException;
->withExceptions(function (Exceptions $exceptions) {
$exceptions->dontReport([
InvalidOrderException::class,
]);
})
In alternativa, puoi semplicemente "marcare" una classe di eccezione con l’interfaccia Illuminate\Contracts\Debug\ShouldntReport
. Quando un’eccezione è marcata con questa interfaccia, non sarà mai segnalata dal gestore delle eccezioni di Laravel:
<?php
namespace App\Exceptions;
use Exception;
use Illuminate\Contracts\Debug\ShouldntReport;
class PodcastProcessingException extends Exception implements ShouldntReport
{
//
}
Internamente, Laravel ignora già alcuni tipi di errori per te, come le eccezioni derivanti da errori HTTP 404 o risposte HTTP 419 generate da token CSRF non validi. Se desideri istruire Laravel a smettere di ignorare un determinato tipo di eccezione, puoi utilizzare il metodo stopIgnoring
nel file bootstrap/app.php
della tua applicazione:
use Symfony\Component\HttpKernel\Exception\HttpException;
->withExceptions(function (Exceptions $exceptions) {
$exceptions->stopIgnoring(HttpException::class);
})
Rendering Exceptions
Per impostazione predefinita, il gestore delle eccezioni di Laravel convertirà automaticamente le eccezioni in una risposta HTTP. Tuttavia, puoi registrare una closure di rendering personalizzata per eccezioni di un determinato tipo. Puoi farlo utilizzando il metodo render
per le eccezioni nel file bootstrap/app.php
della tua applicazione.
La closure passata al metodo render
deve restituire un’istanza di Illuminate\Http\Response
, che può essere generata tramite l’helper response
. Laravel determinerà il tipo di eccezione che la closure gestisce esaminando il type-hint della closure:
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', status: 500);
});
})
Puoi anche utilizzare il metodo render
per sovrascrivere il comportamento di rendering per le eccezioni integrate di Laravel o Symfony, come NotFoundHttpException
. Se la closure fornita al metodo render
non restituisce un valore, verrà utilizzato il rendering predefinito delle eccezioni di Laravel:
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);
}
});
})
Rendering Exceptions as JSON
Quando si visualizza un’eccezione, Laravel determinerà automaticamente se deve essere resa come risposta HTML o JSON in base all’intestazione Accept
della richiesta. Se desideri personalizzare come Laravel decide se rendere le risposte delle eccezioni in HTML o JSON, puoi utilizzare il metodo 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();
});
})
Personalizzare la Risposta alle Eccezioni
Raramente, potresti aver bisogno di personalizzare l’intera risposta HTTP generata dal gestore delle eccezioni di Laravel. Per fare questo, puoi registrare una closure di personalizzazione della risposta usando il metodo respond
:
use Symfony\Component\HttpFoundation\Response;
->withExceptions(function (Exceptions $exceptions) {
$exceptions->respond(function (Response $response) {
if ($response->getStatusCode() === 419) {
return back()->with([
'message' => 'La pagina è scaduta, per favore riprova.',
]);
}
return $response;
});
})
Eccezioni Segnalabili e Renderizzabili
Invece di definire comportamenti personalizzati per la segnalazione e la renderizzazione nel file bootstrap/app.php
della tua applicazione, puoi definire i metodi report
e render
direttamente nelle eccezioni della tua applicazione. Quando questi metodi esistono, verranno automaticamente chiamati dal framework:
<?php
namespace App\Exceptions;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class InvalidOrderException extends Exception
{
/**
* Segnala l'eccezione.
*/
public function report(): void
{
// ...
}
/**
* Renderizza l'eccezione in una risposta HTTP.
*/
public function render(Request $request): Response
{
return response(/* ... */);
}
}
Se la tua eccezione estende un’eccezione che è già renderizzabile, come un’eccezione integrata di Laravel o Symfony, puoi restituire false
dal metodo render
dell’eccezione per renderizzare la risposta HTTP predefinita dell’eccezione:
/**
* Renderizza l'eccezione in una risposta HTTP.
*/
public function render(Request $request): Response|bool
{
if (/** Determina se l'eccezione necessita di una renderizzazione personalizzata */) {
return response(/* ... */);
}
return false;
}
Se la tua eccezione contiene una logica di segnalazione personalizzata che è necessaria solo quando sono soddisfatte determinate condizioni, potrebbe essere necessario istruire Laravel a segnalare a volte l’eccezione utilizzando la configurazione predefinita della gestione delle eccezioni. Per fare ciò, puoi restituire false
dal metodo report
dell’eccezione:
/**
* Segnala l'eccezione.
*/
public function report(): bool
{
if (/** Determina se l'eccezione necessita di una segnalazione personalizzata */) {
// ...
return true;
}
return false;
}
Puoi indicare eventuali dipendenze necessarie del metodo
report
e saranno automaticamente iniettate nel metodo dal contenitore di servizi di Laravel.
Limitazione delle Eccezioni Segnalate
Se la tua applicazione segnala un numero molto elevato di eccezioni, potresti voler limitare quante eccezioni vengono effettivamente registrate o inviate al servizio di monitoraggio degli errori esterno della tua applicazione.
Per prendere un campione casuale delle eccezioni, puoi utilizzare il metodo throttle
delle eccezioni nel file bootstrap/app.php
della tua applicazione. Il metodo throttle
riceve una closure che dovrebbe restituire un’istanza di Lottery
:
use Illuminate\Support\Lottery;
use Throwable;
->withExceptions(function (Exceptions $exceptions) {
$exceptions->throttle(function (Throwable $e) {
return Lottery::odds(1, 1000);
});
})
È anche possibile campionare condizionatamente in base al tipo di eccezione. Se desideri campionare solo le istanze di una specifica classe di eccezioni, puoi restituire un’istanza di Lottery
solo per quella classe:
use App\Exceptions\ApiMonitoringException;
use Illuminate\Support\Lottery;
use Throwable;
->withExceptions(function (Exceptions $exceptions) {
$exceptions->throttle(function (Throwable $e) {
if ($e instanceof ApiMonitoringException) {
return Lottery::odds(1, 1000);
}
});
})
Puoi anche limitare il tasso delle eccezioni registrate o inviate a un servizio di monitoraggio degli errori esterno restituendo un’istanza di Limit
invece di una Lottery
. Questo è utile se vuoi proteggerti da improvvisi picchi di eccezioni che inondano i tuoi log, ad esempio, quando un servizio di terze parti utilizzato dalla tua applicazione è inattivo:
use Illuminate\Broadcasting\BroadcastException;
use Illuminate\Cache\RateLimiting\Limit;
use Throwable;
->withExceptions(function (Exceptions $exceptions) {
$exceptions->throttle(function (Throwable $e) {
if ($e instanceof BroadcastException) {
return Limit::perMinute(300);
}
});
})
Per impostazione predefinita, i limiti utilizzeranno la classe dell’eccezione come chiave di limitazione del tasso. Puoi personalizzare questo specificando la tua chiave utilizzando il metodo by
su Limit
:
use Illuminate\Broadcasting\BroadcastException;
use Illuminate\Cache\RateLimiting\Limit;
use Throwable;
->withExceptions(function (Exceptions $exceptions) {
$exceptions->throttle(function (Throwable $e) {
if ($e instanceof BroadcastException) {
return Limit::perMinute(300)->by($e->getMessage());
}
});
})
Naturalmente, puoi restituire una combinazione di istanze Lottery
e Limit
per diverse eccezioni:
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 $e) {
return match (true) {
$e instanceof BroadcastException => Limit::perMinute(300),
$e instanceof ApiMonitoringException => Lottery::odds(1, 1000),
default => Limit::none(),
};
});
})
Eccezioni HTTP
Alcune eccezioni rappresentano codici di errore HTTP dal server. Ad esempio, può trattarsi di un errore "pagina non trovata" (404), di un "errore di autorizzazione" (401) o anche di un errore 500 generato dallo sviluppatore. Per generare una risposta del genere da qualsiasi parte della tua applicazione, puoi usare l’helper abort
:
abort(404);
Pagine di Errore HTTP Personalizzate
Laravel rende semplice mostrare pagine di errore personalizzate per diversi codici di stato HTTP. Ad esempio, per personalizzare la pagina di errore per il codice di stato HTTP 404, crea un template di vista resources/views/errors/404.blade.php
. Questa vista verrà mostrata per tutti gli errori 404 generati dalla tua applicazione. Le viste in questa cartella devono essere denominate in base al codice di stato HTTP a cui si riferiscono. L’istanza Symfony\Component\HttpKernel\Exception\HttpException
sollevata dalla funzione abort
sarà passata alla vista come variabile $exception
:
<h2>{{ $exception->getMessage() }}</h2>
Puoi pubblicare i template predefiniti delle pagine di errore di Laravel usando il comando Artisan vendor:publish
. Una volta pubblicati i template, puoi personalizzarli come preferisci:
php artisan vendor:publish --tag=laravel-errors
Pagine di Errore HTTP di Fallback
Puoi anche definire una pagina di errore di "fallback" per una determinata serie di codici di stato HTTP. Questa pagina verrà visualizzata se non esiste una pagina corrispondente per il codice di stato HTTP specifico verificatosi. Per fare ciò, definisci un template 4xx.blade.php
e un template 5xx.blade.php
nella directory resources/views/errors
della tua applicazione.
Quando definisci le pagine di errore di fallback, queste pagine non influenzeranno le risposte di errore 404
, 500
e 503
poiché Laravel dispone di pagine interne dedicate per questi codici di stato. Per personalizzare le pagine visualizzate per questi codici di stato, dovresti definire una pagina di errore personalizzata per ciascuno di essi individualmente.