Instradamento (Routing)

Rotte di base

Le route più semplici di Laravel accettano un URI e una chiusura (closure), offrendo un metodo molto semplice ed espressivo per definire route e comportamenti senza complicati file di configurazione del routing:

use Illuminate\Support\Facades\Route;
 
Route::get('/greeting', function () {
    return 'Hello World';
});

I file di percorso predefiniti (The Default Route Files)

Tutte le route di Laravel sono definite nei file di routing, che si trovano nella directory “routes“. Questi file vengono caricati automaticamente dal “App\Providers\RouteServiceProvide” dell’applicazione. Il file routes/web.php definisce le route per l’interfaccia web. Queste route sono assegnate al gruppo di middleware “web“, che fornisce funzionalità come lo stato della sessione e la protezione CSRF. Le route nel file routes/api.php sono stateless e sono assegnate al gruppo di middleware “api“.

Per la maggior parte delle applicazioni, inizierai definendo le route nel file routes/web.php. Le route definite in questo file possono essere accessibili inserendo l’URL della route definita nel tuo browser. Ad esempio, puoi accedere alla seguente route navigando su http://example.com/user nel tuo browser:

use App\Http\Controllers\UserController;
 
Route::get('/user', [UserController::class, 'index']);

Le route definite nel file routes/api.php sono annidate all’interno di un gruppo di route gestito dal RouteServiceProvider. All’interno di questo gruppo, il prefisso URI /api viene automaticamente applicato, quindi non è necessario applicarlo manualmente ad ogni route nel file. Puoi modificare il prefisso e altre opzioni del gruppo di route modificando la classe RouteServiceProvider.

Metodi router disponibili

Il router consente di registrare percorsi che rispondono a qualsiasi verbo HTTP:

Route::get($uri, $callback);
Route::post($uri, $callback);
Route::put($uri, $callback);
Route::patch($uri, $callback);
Route::delete($uri, $callback);
Route::options($uri, $callback);

A volte potresti aver bisogno di registrare una route che risponde a più verbi HTTP. Puoi farlo utilizzando il metodo match. Oppure, puoi registrare una route che risponde a tutti i verbi HTTP utilizzando il metodo any.

Route::match(['get', 'post'], '/', function () {
    // ...
});
 
Route::any('/', function () {
    // ...
});

Quando si definiscono più route che condividono la stessa URI, le route che utilizzano i metodi get, post, put, patch, delete e options dovrebbero essere definite prima delle route che utilizzano i metodi any, match e redirect. Questo garantisce che la richiesta in ingresso venga associata alla route corretta.

Iniezione di dipendenza (Dependency Injection)

È possibile specificare come dipendenza qualsiasi oggetto richiesto dalla route nella firma del callback della route. Le dipendenze dichiarate saranno automaticamente risolte e iniettate nel callback tramite il container dei servizi di Laravel. Ad esempio, è possibile specificare come dipendenza la classe Illuminate\Http\Request per ottenere l’oggetto della richiesta HTTP corrente automaticamente iniettato nel callback della route:

use Illuminate\Http\Request;
 
Route::get('/users', function (Request $request) {
    // ...
});

Protezione CSRF

Ricorda, qualsiasi form HTML che punta a route POST, PUT, PATCH o DELETE definite nel file delle route web dovrebbe includere un campo del token CSRF. In caso contrario, la richiesta verrà rifiutata. Puoi leggere ulteriori informazioni sulla protezione CSRF nella documentazione relativa al CSRF.

<form method="POST" action="/profile">
    @csrf
    ...
</form>

Percorsi di reindirizzamento (Redirect Routes)

Se stai definendo una route che reindirizza a un’altra URI, puoi utilizzare il metodo Route::redirect. Questo metodo fornisce un comodo shortcut che ti evita di dover definire una route completa o un controller per eseguire un semplice reindirizzamento.

Route::redirect('/here', '/there');

Per impostazione predefinita, Route::redirect restituisce un codice di stato 302. Puoi personalizzare il codice di stato utilizzando il terzo parametro opzionale.

Route::redirect('/here', '/there', 301);

Oppure, puoi utilizzare il metodo Route::permanentRedirect per restituire un codice di stato 301.

Route::permanentRedirect('/here', '/there');

Quando si utilizzano i parametri di percorso nelle rotte di reindirizzamento, i seguenti parametri sono riservati da Laravel e non possono essere utilizzati: “destination” e “status“.

Visualizza Percorsi (View Routes)

Se la tua rotta deve solo restituire una vista, puoi utilizzare il metodo Route::view. Come il metodo redirect, questo metodo fornisce un semplice shortcut che ti permette di non dover definire una rotta completa o un controller. Il metodo view accetta come primo argomento un URI e come secondo argomento il nome della vista. Inoltre, puoi fornire un array di dati da passare alla vista come terzo argomento opzionale:

Route::view('/welcome', 'welcome');
 
Route::view('/welcome', 'welcome', ['name' => 'Taylor']);

Quando si utilizzano i parametri delle rotte nelle rotte delle viste, i seguenti parametri sono riservati da Laravel e non possono essere utilizzati: view, data, status e headers.

L’elenco dei percorsi (The Route List)

Il comando Artisan route:list può fornire facilmente una panoramica di tutte le rotte definite dalla tua applicazione:

php artisan route:list

Per impostazione predefinita, il comando route:list non mostra i middleware di route assegnati a ciascuna rotta; tuttavia, è possibile istruire Laravel a visualizzare i middleware di route aggiungendo l’opzione -v al comando:

php artisan route:list -v

Puoi anche istruire Laravel a mostrare solo le rotte che iniziano con una determinata URI:

php artisan route:list --path=api

Inoltre, puoi istruire Laravel a nascondere tutte le rotte definite da pacchetti di terze parti fornendo l’opzione –except-vendor al momento dell’esecuzione del comando route:list:

php artisan route:list --except-vendor

Allo stesso modo, puoi anche istruire Laravel a mostrare solo le rotte definite dai pacchetti di terze parti fornendo l’opzione –only-vendor al momento dell’esecuzione del comando route:list:

php artisan route:list --only-vendor

Parametri percorso (Route Parameters)

Parametri richiesti

A volte sarà necessario catturare segmenti dell’URI all’interno della tua rotta. Ad esempio, potresti aver bisogno di catturare l’ID di un utente dall’URL. Puoi farlo definendo dei parametri di rotta:

Route::get('/user/{id}', function (string $id) {
    return 'User '.$id;
});

Puoi definire quanti parametri di rotta sono necessari per la tua rotta:

Route::get('/posts/{post}/comments/{comment}', function (string $postId, string $commentId) {
    // ...
});

I parametri di rotta sono sempre racchiusi tra parentesi graffe {} e dovrebbero consistere di caratteri alfabetici. Sono accettati anche gli underscore (_) all’interno dei nomi dei parametri di rotta. I parametri di rotta vengono inseriti nei callback delle rotte o nei controller in base al loro ordine: i nomi degli argomenti del callback o del controller non sono rilevanti.

Parametri e iniezione di dipendenza

Se la tua rotta ha delle dipendenze che desideri che il service container di Laravel inietti automaticamente nel callback della tua rotta, dovresti elencare i parametri di rotta dopo le tue dipendenze.

use Illuminate\Http\Request;
 
Route::get('/user/{id}', function (Request $request, string $id) {
    return 'User '.$id;
});

Parametri facoltativi

Occasionalmente potresti dover specificare un parametro di rotta che potrebbe non essere sempre presente nell’URI. Puoi farlo inserendo un punto interrogativo (?) dopo il nome del parametro. Assicurati di assegnare al corrispondente variabile della rotta un valore predefinito.

Route::get('/user/{name?}', function (string $name = null) {
    return $name;
});
 
Route::get('/user/{name?}', function (string $name = 'John') {
    return $name;
});

Vincoli di espressione regolare

Puoi limitare il formato dei parametri di una rotta utilizzando il metodo where su un’istanza di rotta. Il metodo where accetta il nome del parametro e un’espressione regolare che definisce come il parametro dovrebbe essere limitato:

Route::get('/user/{name}', function (string $name) {
    // ...
})->where('name', '[A-Za-z]+');
 
Route::get('/user/{id}', function (string $id) {
    // ...
})->where('id', '[0-9]+');
 
Route::get('/user/{id}/{name}', function (string $id, string $name) {
    // ...
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);

Per comodità, alcune espressioni regolari comunemente utilizzate hanno metodi di supporto che ti consentono di aggiungere rapidamente vincoli di pattern alle tue rotte:

Route::get('/user/{id}/{name}', function (string $id, string $name) {
    // ...
})->whereNumber('id')->whereAlpha('name');
 
Route::get('/user/{name}', function (string $name) {
    // ...
})->whereAlphaNumeric('name');
 
Route::get('/user/{id}', function (string $id) {
    // ...
})->whereUuid('id');
 
Route::get('/user/{id}', function (string $id) {
    //
})->whereUlid('id');
 
Route::get('/category/{category}', function (string $category) {
    // ...
})->whereIn('category', ['movie', 'song', 'painting']);

Se la richiesta in arrivo non corrisponde ai vincoli del pattern della rotta, verrà restituita una risposta HTTP 404.

Vincoli globali

Se desideri che un parametro di rotta sia sempre vincolato da una data espressione regolare, puoi utilizzare il metodo pattern. Dovresti definire questi vincoli nel metodo boot della classe App\Providers\RouteServiceProvider:

/**
 * Define your route model bindings, pattern filters, etc.
 */
public function boot(): void
{
    Route::pattern('id', '[0-9]+');
}

Una volta che il pattern è stato definito, viene automaticamente applicato a tutte le rotte che utilizzano quel nome di parametro:

Route::get('/user/{id}', function (string $id) {
    // Only executed if {id} is numeric...
});

barre oblique in avanti

Il componente di routing di Laravel consente la presenza di tutti i caratteri tranne / all’interno dei valori dei parametri delle rotte. Devi consentire esplicitamente / come parte del tuo segnaposto utilizzando una condizione di espressione regolare in cui.

Route::get('/search/{search}', function (string $search) {
    return $search;
})->where('search', '.*');

Le barre oblique in avanti codificate sono supportate solo nell’ultimo segmento della rotta.

Percorsi denominati (Named Routes)

Le rotte denominate consentono la generazione conveniente di URL o reindirizzamenti per rotte specifiche. Puoi specificare un nome per una rotta concatenando il metodo name alla definizione della rotta:

Route::get('/user/profile', function () {
    // ...
})->name('profile');

Puoi anche specificare i nomi delle rotte per le azioni del controller:

Route::get(
    '/user/profile',
    [UserProfileController::class, 'show']
)->name('profile');

I nomi delle rotte devono essere sempre univoci.

Generazione di URL per rotte denominate

Una volta assegnato un nome a una determinata rotta, è possibile utilizzare il nome della rotta per generare URL o reindirizzamenti tramite le funzioni helper route e redirect di Laravel:

// Generating URLs...
$url = route('profile');
 
// Generating Redirects...
return redirect()->route('profile');
 
return to_route('profile');

Se la rotta denominata definisce dei parametri, è possibile passare i parametri come secondo argomento alla funzione route. I parametri forniti verranno automaticamente inseriti nell’URL generato nelle posizioni corrette:

Route::get('/user/{id}/profile', function (string $id) {
    // ...
})->name('profile');
 
$url = route('profile', ['id' => 1]);

Se si passano ulteriori parametri nell’array, quelle coppie chiave/valore saranno automaticamente aggiunte alla stringa di query dell’URL generato:

Route::get('/user/{id}/profile', function (string $id) {
    // ...
})->name('profile');
 
$url = route('profile', ['id' => 1, 'photos' => 'yes']);
 
// /user/1/profile?photos=yes

A volte potresti voler specificare valori predefiniti a livello di richiesta per i parametri dell’URL, come ad esempio la lingua corrente. Per fare ciò, puoi utilizzare il metodo URL::defaults.

Ispezione del percorso corrente

Se desideri determinare se la richiesta corrente è stata instradata verso una determinata route con nome, puoi utilizzare il metodo named su un’istanza di Route. Ad esempio, puoi controllare il nome della route corrente da un middleware di route:

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
 
/**
 * Handle an incoming request.
 *
 * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
 */
public function handle(Request $request, Closure $next): Response
{
    if ($request->route()->named('profile')) {
        // ...
    }
 
    return $next($request);
}

Gruppi di percorsi

I gruppi di route ti consentono di condividere attributi di route, come i middleware, su un gran numero di route senza doverli definire su ogni singola route.

I gruppi nidificati cercano di “unire” intelligentemente gli attributi con il gruppo genitore. I middleware e le condizioni di “where” vengono uniti, mentre i nomi e i prefissi vengono concatenati. I delimitatori di namespace e le barre nei prefissi URI vengono aggiunti automaticamente dove appropriato.

Middleware

Per assegnare il middleware a tutti i percorsi all’interno di un gruppo, è possibile utilizzare il metodo middleware prima di definire il gruppo. I middleware vengono eseguiti nell’ordine in cui sono elencati nell’array:

Route::middleware(['first', 'second'])->group(function () {
    Route::get('/', function () {
        // Uses first & second middleware...
    });
 
    Route::get('/user/profile', function () {
        // Uses first & second middleware...
    });
});

Controllers

Se un gruppo di percorsi utilizza lo stesso controller, è possibile utilizzare il metodo controller per definire il controller comune per tutti i percorsi all’interno del gruppo. Successivamente, quando si definiscono i percorsi, è sufficiente fornire il metodo controller che essi richiamano:

use App\Http\Controllers\OrderController;
 
Route::controller(OrderController::class)->group(function () {
    Route::get('/orders/{id}', 'show');
    Route::post('/orders', 'store');
});

Instradamento sottodominio

I gruppi di percorsi possono essere utilizzati anche per gestire il routing dei sottodomini. I sottodomini possono essere assegnati come parametri di percorso, proprio come le URI dei percorsi, consentendo di catturare una porzione del sottodominio per l’utilizzo nel percorso o nel controller. Il sottodominio può essere specificato chiamando il metodo domain prima di definire il gruppo:

Route::domain('{account}.example.com')->group(function () {
    Route::get('user/{id}', function (string $account, string $id) {
        // ...
    });
});

Per garantire che i percorsi dei sottodomini siano raggiungibili, è necessario registrare i percorsi dei sottodomini prima di registrare i percorsi del dominio principale. In questo modo si evita che i percorsi del dominio principale sovrascrivano i percorsi dei sottodomini che hanno lo stesso percorso URI.

Prefisso delle Rotte

Il metodo prefix può essere utilizzato per aggiungere un prefisso a ciascun percorso nel gruppo con un determinato URI. Ad esempio, potresti voler aggiungere il prefisso admin a tutti i percorsi del gruppo:

Route::prefix('admin')->group(function () {
    Route::get('/users', function () {
        // Matches The "/admin/users" URL
    });
});

Prefissi del nome del percorso

Il metodo name può essere utilizzato per aggiungere un prefisso a ciascun nome di percorso nel gruppo con una determinata stringa. Ad esempio, potresti voler aggiungere il prefisso “admin” a tutti i nomi dei percorsi nel gruppo. La stringa fornita viene aggiunta come prefisso al nome del percorso esattamente come specificato, quindi assicurati di includere il carattere “.” finale nel prefisso:

Route::name('admin.')->group(function () {
    Route::get('/users', function () {
        // Route assigned name "admin.users"...
    })->name('users');
});

Associazione del modello di percorso (Route Model Binding)

Quando si inietta l’ID di un modello in un percorso o in un’azione del controller, spesso è necessario interrogare il database per recuperare il modello corrispondente a quell’ID. Il route model binding di Laravel fornisce un modo pratico per iniettare automaticamente le istanze dei modelli direttamente nei percorsi. Ad esempio, anziché iniettare l’ID di un utente, è possibile iniettare l’intera istanza del modello User che corrisponde all’ID fornito.

Implicit Binding

Laravel risolve automaticamente i modelli Eloquent definiti nelle route o nelle azioni del controller quando i nomi delle variabili con type-hint corrispondono a un segmento di route. Ad esempio:

use App\Models\User;
 
Route::get('/users/{user}', function (User $user) {
    return $user->email;
});

Dal momento che la variabile $user è di tipo App\Models\User e il nome della variabile corrisponde al segmento di URI {user}, Laravel inietterà automaticamente l’istanza del modello che ha un ID corrispondente al valore corrispondente dell’URI della richiesta. Se non viene trovata alcuna istanza del modello corrispondente nel database, verrà generata automaticamente una risposta HTTP 404.

Naturalmente, l’implicit binding è possibile anche quando si utilizzano i metodi del controller. Ancora una volta, nota che il segmento di URI {user} corrisponde alla variabile $user nel controller che contiene un type-hint App\Models\User:

use App\Http\Controllers\UserController;
use App\Models\User;
 
// Route definition...
Route::get('/users/{user}', [UserController::class, 'show']);
 
// Controller method definition...
public function show(User $user)
{
    return view('user.profile', ['user' => $user]);
}

Soft Deleted Models

Di solito, l’implicit model binding non recupera modelli che sono stati eliminati in modo soft. Tuttavia, è possibile istruire l’implicit binding a recuperare anche questi modelli concatenando il metodo withTrashed alla definizione della route:

use App\Models\User;
 
Route::get('/users/{user}', function (User $user) {
    return $user->email;
})->withTrashed();

Personalizzazione della chiave (Personalizzazione della chiave)

A volte potresti voler risolvere i modelli Eloquent utilizzando una colonna diversa da id. Per farlo, puoi specificare la colonna nella definizione del parametro di percorso:

use App\Models\Post;
 
Route::get('/posts/{post:slug}', function (Post $post) {
    return $post;
});

Se desideri che il model binding utilizzi sempre una colonna del database diversa da id quando recupera una determinata classe di modello, puoi sovrascrivere il metodo getRouteKeyName nel modello Eloquent:

/**
 * Get the route key for the model.
 */
public function getRouteKeyName(): string
{
    return 'slug';
}

Chiavi personalizzate e ambiti

Quando associ due o più modelli Eloquent in modo implicito nella definizione di una singola rotta, potresti voler limitare il secondo modello Eloquent affinché sia un figlio del modello Eloquent precedente. Ad esempio, considera questa definizione di rotta che recupera un post di un blog tramite lo slug per un utente specifico:

use App\Models\Post;
use App\Models\User;
 
Route::get('/users/{user}/posts/{post:slug}', function (User $user, Post $post) {
    return $post;
});

Quando utilizzi un binding implicito personalizzato come parametro di una rotta nidificata, Laravel effettuerà automaticamente una query per recuperare il modello nidificato tramite il suo genitore, utilizzando delle convenzioni per indovinare il nome della relazione sul genitore. In questo caso, si suppone che il modello User abbia una relazione chiamata posts (la forma plurale del nome del parametro di rotta) che può essere utilizzata per recuperare il modello Post.

Se desideri, puoi istruire Laravel a limitare i binding “figlio” anche quando non viene fornita una chiave personalizzata. Per farlo, puoi invocare il metodo scopeBindings durante la definizione della tua rotta:

use App\Models\Post;
use App\Models\User;
 
Route::get('/users/{user}/posts/{post}', function (User $user, Post $post) {
    return $post;
})->scopeBindings();

Oppure, puoi istruire un intero gruppo di definizioni di route a utilizzare binding con ambito limitato:

Route::scopeBindings()->group(function () {
    Route::get('/users/{user}/posts/{post}', function (User $user, Post $post) {
        return $post;
    });
});

Allo stesso modo, puoi esplicitamente istruire Laravel a non limitare gli ambiti dei binding invocando il metodo withoutScopedBindings:

Route::get('/users/{user}/posts/{post:slug}', function (User $user, Post $post) {
    return $post;
})->withoutScopedBindings();

Personalizzazione del comportamento per i modelli mancanti:

Di solito, se un modello implicitamente vincolato non viene trovato, viene generata una risposta HTTP 404. Tuttavia, è possibile personalizzare questo comportamento chiamando il metodo missing durante la definizione della rotta. Il metodo missing accetta una chiusura (closure) che verrà invocata se un modello implicitamente vincolato non può essere trovato:

use App\Http\Controllers\LocationsController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;
 
Route::get('/locations/{location:slug}', [LocationsController::class, 'show'])
        ->name('locations.view')
        ->missing(function (Request $request) {
            return Redirect::route('locations.index');
        });

Implicit Enum Binding

PHP 8.1 ha introdotto il supporto per gli Enumeratori (Enums). Per completare questa funzionalità, Laravel consente di utilizzare il type-hint di un Enum supportato da stringhe nella definizione della route e Laravel invocherà la route solo se il segmento di quella route corrisponde a un valore valido dell’Enum. In caso contrario, verrà restituita automaticamente una risposta HTTP 404. Ad esempio, dato il seguente Enum:

<?php
 
namespace App\Enums;
 
enum Category: string
{
    case Fruits = 'fruits';
    case People = 'people';
}

Puoi definire una route che verrà invocata solo se il segmento di route {category} è “fruits” o “people“. In caso contrario, Laravel restituirà una risposta HTTP 404:

use App\Enums\Category;
use Illuminate\Support\Facades\Route;
 
Route::get('/categories/{category}', function (Category $category) {
    return $category->value;
});

Vincolo Esplicito (Explicit Binding)

Non sei obbligato a utilizzare la risoluzione del modello di Laravel in base a convenzioni implicite per utilizzare il model binding. Puoi anche definire esplicitamente come i parametri delle route corrispondono ai modelli. Per registrare un binding esplicito, utilizza il metodo model del router per specificare la classe per un dato parametro. Dovresti definire i binding espliciti del modello all’inizio del metodo boot della tua classe RouteServiceProvider:

use App\Models\User;
use Illuminate\Support\Facades\Route;
 
/**
 * Define your route model bindings, pattern filters, etc.
 */
public function boot(): void
{
    Route::model('user', User::class);
 
    // ...
}

Successivamente, definisci una route che contenga un parametro {user}:

use App\Models\User;
 
Route::get('/users/{user}', function (User $user) {
    // ...
});

Poiché abbiamo associato tutti i parametri {user} al modello App\Models\User, un’istanza di quella classe verrà iniettata nella route. Ad esempio, una richiesta a users/1 inietterà l’istanza di User dal database con ID 1.

Se non viene trovata un’istanza del modello corrispondente nel database, verrà generata automaticamente una risposta HTTP 404.

Personalizzazione della logica di risoluzione (Customizing The Resolution Logic)

Se desideri definire la tua logica di risoluzione per il binding dei modelli, puoi utilizzare il metodo Route::bind. La funzione di chiusura che passi al metodo bind riceverà il valore del segmento dell’URI e dovrebbe restituire l’istanza della classe che deve essere iniettata nella route. Anche questa personalizzazione dovrebbe avvenire nel metodo boot del tuo RouteServiceProvider dell’applicazione.

use App\Models\User;
use Illuminate\Support\Facades\Route;
 
/**
 * Define your route model bindings, pattern filters, etc.
 */
public function boot(): void
{
    Route::bind('user', function (string $value) {
        return User::where('name', $value)->firstOrFail();
    });
 
    // ...
}

In alternativa, puoi sovrascrivere il metodo resolveRouteBinding sul tuo modello Eloquent. Questo metodo riceverà il valore del segmento dell’URI e dovrebbe restituire l’istanza della classe che deve essere iniettata nella route.

/**
 * Retrieve the model for a bound value.
 *
 * @param  mixed  $value
 * @param  string|null  $field
 * @return \Illuminate\Database\Eloquent\Model|null
 */
public function resolveRouteBinding($value, $field = null)
{
    return $this->where('name', $value)->firstOrFail();
}

Se una route utilizza l’implicit binding con scoping, verrà utilizzato il metodo resolveChildRouteBinding per risolvere il legame figlio del modello genitore.

/**
 * Retrieve the child model for a bound value.
 *
 * @param  string  $childType
 * @param  mixed  $value
 * @param  string|null  $field
 * @return \Illuminate\Database\Eloquent\Model|null
 */
public function resolveChildRouteBinding($childType, $value, $field)
{
    return parent::resolveChildRouteBinding($childType, $value, $field);
}

Percorsi di riserva (Fallback Routes)

Utilizzando il metodo Route::fallback, puoi definire una route che verrà eseguita quando nessun’altra route corrisponde alla richiesta in ingresso. Di solito, le richieste non gestite renderanno automaticamente una pagina “404” tramite il gestore delle eccezioni dell’applicazione. Tuttavia, poiché di solito definisci la route fallback nel file routes/web.php, tutti i middleware nel gruppo di middleware web saranno applicati alla route. Se necessario, puoi aggiungere ulteriori middleware a questa route.

Route::fallback(function () {
    // ...
});

La route fallback dovrebbe sempre essere l’ultima route registrata dalla tua applicazione.

Limitazione della frequenza (Rate Limiting)

Definire i Limitatori di Velocità (Defining Rate Limiters)

Laravel include potenti e personalizzabili servizi di limitazione della velocità che è possibile utilizzare per restrizioni la quantità di traffico per una determinata route o gruppo di route. Per iniziare, dovresti definire le configurazioni dei limitatori di velocità che soddisfino le esigenze della tua applicazione.

Di solito, i limitatori di velocità vengono definiti all’interno del metodo “boot” della classe App\Providers\RouteServiceProvider della tua applicazione. In realtà, questa classe già include una definizione di limitatore di velocità che viene applicata alle route nel file routes/api.php della tua applicazione.

use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
 
/**
 * Define your route model bindings, pattern filters, and other route configuration.
 */
protected function boot(): void
{
    RateLimiter::for('api', function (Request $request) {
        return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
    });
 
    // ...
}

I limitatori di velocità vengono definiti utilizzando il metodo “for” della facciata RateLimiter. Il metodo “for” accetta un nome per il limitatore di velocità e una funzione di chiusura che restituisce la configurazione del limite che dovrebbe essere applicata alle route assegnate al limitatore di velocità. La configurazione del limite è costituita da istanze della classe Illuminate\Cache\RateLimiting\Limit. Questa classe contiene utili metodi “builder” che ti consentono di definire rapidamente il limite. Il nome del limitatore di velocità può essere qualsiasi stringa desideri.

use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
 
/**
 * Define your route model bindings, pattern filters, and other route configuration.
 */
protected function boot(): void
{
    RateLimiter::for('global', function (Request $request) {
        return Limit::perMinute(1000);
    });
 
    // ...
}

Se la richiesta in arrivo supera il limite di velocità specificato, Laravel restituirà automaticamente una risposta con il codice di stato HTTP 429. Se desideri definire la tua risposta personalizzata da restituire in caso di limite di velocità, puoi utilizzare il metodo “response“:

RateLimiter::for('global', function (Request $request) {
    return Limit::perMinute(1000)->response(function (Request $request, array $headers) {
        return response('Custom response...', 429, $headers);
    });
});

Since rate limiter callbacks receive the incoming HTTP request instance, you may build the appropriate rate limit dynamically based on the incoming request or authenticated user:

RateLimiter::for('uploads', function (Request $request) {
    return $request->user()->vipCustomer()
                ? Limit::none()
                : Limit::perMinute(100);
});

Segmentare i limiti di velocità

A volte potresti desiderare di segmentare i limiti di velocità in base a un valore arbitrario. Ad esempio, potresti voler consentire agli utenti di accedere a una determinata route 100 volte al minuto per indirizzo IP. Per fare ciò, puoi utilizzare il metodo “by” quando definisci il tuo limite di velocità:

RateLimiter::for('uploads', function (Request $request) {
    return $request->user()->vipCustomer()
                ? Limit::none()
                : Limit::perMinute(100)->by($request->ip());
});

Per illustrare questa funzionalità con un altro esempio, possiamo limitare l’accesso alla route a 100 volte al minuto per utente autenticato (ID utente) o 10 volte al minuto per indirizzo IP per gli ospiti (utenti non autenticati):

RateLimiter::for('uploads', function (Request $request) {
    return $request->user()
                ? Limit::perMinute(100)->by($request->user()->id)
                : Limit::perMinute(10)->by($request->ip());
});

Limiti multipli

Se necessario, puoi restituire un array di limiti di velocità per una determinata configurazione del limitatore di velocità. Ogni limite di velocità verrà valutato per il percorso in base all’ordine in cui sono posizionati nell’array.

RateLimiter::for('login', function (Request $request) {
    return [
        Limit::perMinute(500),
        Limit::perMinute(3)->by($request->input('email')),
    ];
});

Associare i limitatori di velocità alle rotte

I limitatori di velocità possono essere collegati alle rotte o ai gruppi di rotte utilizzando il middlewarethrottle“. Il middleware “throttle” accetta il nome del limitatore di velocità che desideri assegnare alla rotta.

Route::middleware(['throttle:uploads'])->group(function () {
    Route::post('/audio', function () {
        // ...
    });
 
    Route::post('/video', function () {
        // ...
    });
});

Il throttling con Redis

Normalmente, il middleware di throttle è mappato alla classe Illuminate\Routing\Middleware\ThrottleRequests. Questa mappatura è definita nel kernel HTTP della tua applicazione (App\Http\Kernel). Tuttavia, se stai utilizzando Redis come cache driver dell’applicazione, potresti desiderare di cambiare questa mappatura per utilizzare la classe Illuminate\Routing\Middleware\ThrottleRequestsWithRedis. Questa classe è più efficiente nel gestire il rate limiting utilizzando Redis.

'throttle' => \Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class,

Spoofing del metodo del modulo

I moduli HTML non supportano le azioni PUT, PATCH o DELETE. Pertanto, quando si definiscono percorsi PUT, PATCH o DELETE che vengono chiamati da un modulo HTML, è necessario aggiungere un campo nascosto _method al modulo. Il valore inviato con il campo _method verrà utilizzato come metodo della richiesta HTTP.

<form action="/example" method="POST">
    <input type="hidden" name="_method" value="PUT">
    <input type="hidden" name="_token" value="{{ csrf_token() }}">
</form>

Per comodità, puoi utilizzare la direttiva Blade @method per generare il campo di input _method:

<form action="/example" method="POST">
    @method('PUT')
    @csrf
</form>

Accesso al percorso corrente

Puoi utilizzare i metodi current, currentRouteName e currentRouteAction sulla facciata Route per accedere alle informazioni sulla route che gestisce la richiesta in arrivo:

use Illuminate\Support\Facades\Route;
 
$route = Route::current(); // Illuminate\Routing\Route
$name = Route::currentRouteName(); // string
$action = Route::currentRouteAction(); // string

Puoi consultare la documentazione API sia per la classe sottostante della facade Route che per l’istanza di Route per rivedere tutti i metodi disponibili sulle classi del router e delle route.

Condivisione delle risorse tra le origini (CORS)

Laravel può rispondere automaticamente alle richieste HTTP OPTIONS di CORS con i valori che hai configurato. Tutte le impostazioni di CORS possono essere configurate nel file di configurazione config/cors.php della tua applicazione. Le richieste OPTIONS verranno gestite automaticamente dal middleware HandleCors che è incluso per impostazione predefinita nel tuo stack di middleware globale. Il tuo stack di middleware globale si trova nel file HTTP kernel della tua applicazione (App\Http\Kernel).

Per ulteriori informazioni su CORS e le intestazioni CORS, consulta la documentazione web di MDN su CORS.

Cache del percorso

Quando distribuisci la tua applicazione in produzione, dovresti sfruttare la cache delle route di Laravel. Utilizzare la cache delle route diminuirà drasticamente il tempo necessario per registrare tutte le route dell’applicazione. Per generare una cache delle route, esegui il comando Artisan route:cache:

php artisan route:cache

Dopo aver eseguito questo comando, il file delle route in cache verrà caricato ad ogni richiesta. Ricorda, se aggiungi nuove route dovrai generare una nuova cache delle route. Per questo motivo, dovresti eseguire il comando route:cache solo durante la distribuzione del tuo progetto.

Puoi utilizzare il comando route:clear per eliminare la cache delle route:

php artisan route:clear