Laravel cung cấp một số helper để hỗ trợ bạn tạo URL cho application của bạn. Những helper này chủ yếu hữu ích khi tạo link trong các template và API response hoặc khi tạo response chuyển hướng đến một phần khác trong application của bạn.
Helper url có thể được sử dụng để tạo các URL tùy biến cho application của bạn. URL được tạo ra sẽ tự động sử dụng scheme (HTTP hoặc HTTPS) và host từ request hiện tại đang được xử lý bởi ứng dụng:
$post = App\Models\Post::find(1);
echo url("/posts/{$post->id}");
// http://example.com/posts/1
Để tạo ra một URL với các tham số query string, bạn có thể sử dụng phương thức query:
echo url()->query('/posts', ['search' => 'Laravel']);
// https://example.com/posts?search=Laravel
echo url()->query('/posts?sort=latest', ['search' => 'Laravel']);
// http://example.com/posts?sort=latest&search=Laravel
Việc cung cấp các tham số query string đã tồn tại trong path sẽ ghi đè lên giá trị hiện có của chúng:
echo url()->query('/posts?sort=latest', ['sort' => 'oldest']);
// http://example.com/posts?sort=oldest
Các mảng giá trị cũng có thể được truyền dưới dạng tham số query string. Các giá trị này sẽ được gán key và mã hóa đúng cách trong URL được tạo ra:
echo $url = url()->query('/posts', ['columns' => ['title', 'body']]);
// http://example.com/posts?columns%5B0%5D=title&columns%5B1%5D=body
echo urldecode($url);
// http://example.com/posts?columns[0]=title&columns[1]=body
Nếu như không có đường dẫn nào được truyền vào cho helper url, thì một instance Illuminate\Routing\UrlGenerator sẽ được trả về, cho phép bạn truy cập vào thông tin về URL hiện tại:
// Get the current URL without the query string...
echo url()->current();
// Get the current URL including the query string...
echo url()->full();
Mỗi phương thức này cũng có thể được truy cập thông qua facade URL:
use Illuminate\Support\Facades\URL;
echo URL::current();
Thỉnh thoảng việc biết URL trước đó mà người dùng vừa truy cập sẽ rất hữu ích. Bạn có thể truy cập vào URL trước đó thông qua các phương thức previous và previousPath của helper url:
// Get the full URL for the previous request...
echo url()->previous();
// Get the path for the previous request...
echo url()->previousPath();
Hoặc, thông qua session, bạn có thể truy cập vào URL trước đó dưới dạng một instance URI:
use Illuminate\Http\Request;
Route::post('/users', function (Request $request) {
$previousUri = $request->session()->previousUri();
// ...
});
Bạn cũng có thể lấy tên route của URL đã truy cập trước đó thông qua session:
$previousRoute = $request->session()->previousRoute();
Helper route có thể được sử dụng để tạo URL tới một route đã được đặt tên. Các route đã được đặt tên cho phép bạn tạo URL mà không cần phải biết URL thực tế đang được định nghĩa như thế nào. Do đó, nếu URL của route có thay đổi, thì bạn cũng không cần phải thực hiện thay đổi gì cho các lệnh gọi hàm route của bạn. Ví dụ: hãy tưởng tượng application của bạn chứa một route đang được định nghĩa như sau:
Route::get('/post/{post}', function (Post $post) {
// ...
})->name('post.show');
Để tạo URL tới route này, bạn có thể sử dụng helper route như sau:
echo route('post.show', ['post' => 1]);
// http://example.com/post/1
Dĩ nhiên, helper route cũng có thể được sử dụng để tạo URL cho các route có nhiều tham số:
Route::get('/post/{post}/comment/{comment}', function () {
// ...
})->name('comment.show');
echo route('comment.show', ['post' => 1, 'comment' => 3]);
// http://example.com/post/1/comment/3
Bất kỳ phần tử bổ sung nào không tương ứng với các tham số định nghĩa trên route sẽ được thêm vào chuỗi truy vấn của URL:
echo route('post.show', ['post' => 1, 'search' => 'rocket']);
// http://example.com/post/1?search=rocket
Bạn sẽ thường tạo URL bằng cách sử dụng route key (thường là khóa chính) của model Eloquent. Vì lý do này, bạn có thể truyền các model Eloquent làm giá trị tham số. Helper route sẽ tự động lấy route key của model:
echo route('post.show', ['post' => $post]);
Laravel cho phép bạn dễ dàng tạo các URL "signed" tới các route đã được đặt tên. Các URL này có một "signed" hash được thêm vào sau chuỗi truy vấn cho phép Laravel xác minh được rằng URL sẽ không bị sửa kể từ khi nó được tạo ra. URL signed đặc biệt hữu ích cho các route có thể truy cập công khai nhưng cần thêm một lớp bảo vệ để chống lại việc sửa đổi URL.
Ví dụ: bạn có thể sử dụng các signed URL để tạo link "hủy đăng ký" được gửi qua email cho khách hàng của bạn. Để tạo một signed URL cho một route đã được đặt tên, hãy sử dụng phương thức signedRoute trong facade URL:
use Illuminate\Support\Facades\URL;
return URL::signedRoute('unsubscribe', ['user' => 1]);
Bạn có thể bỏ tên miền ra khỏi signed URL hash bằng cách cung cấp tham số absolute cho phương thức signedRoute:
return URL::signedRoute('unsubscribe', ['user' => 1], absolute: false);
Nếu bạn muốn tạo một route URL signed tạm thời sau một khoảng thời gian xác định, bạn có thể sử dụng phương thức temporarySignedRoute. Khi Laravel xác thực một route URL signed tạm thời, nó sẽ đảm bảo rằng giá trị timestamp hết hạn được mã hóa vào trong URL signed sẽ chưa hết hạn:
use Illuminate\Support\Facades\URL;
return URL::temporarySignedRoute(
'unsubscribe', now()->addMinutes(30), ['user' => 1]
);
Để xác minh một request có signed hợp lệ hay không, bạn có thể gọi phương thức hasValidSignature trên instance Illuminate\Http\Request đó:
use Illuminate\Http\Request;
Route::get('/unsubscribe/{user}', function (Request $request) {
if (! $request->hasValidSignature()) {
abort(401);
}
// ...
})->name('unsubscribe');
Thỉnh thoảng, bạn có thể cần cho phép frontend của ứng dụng thêm dữ liệu vào một signed URL, chẳng hạn như khi thực hiện phân trang ở client-side. Do đó, bạn có thể chỉ định các tham số request cần được bỏ qua khi xác thực signed URL bằng phương thức hasValidSignatureWhileIgnoring. Hãy nhớ rằng, việc bỏ qua các tham số này sẽ cho phép bất kỳ ai cũng có thể sửa các tham số đó trong request:
if (! $request->hasValidSignatureWhileIgnoring(['page', 'order'])) {
abort(401);
}
Thay vì xác thực các signed URL bằng cách sử dụng instance request, bạn có thể gán một middleware signed (Illuminate\Routing\Middleware\ValidateSignature) cho một route. Nếu request đến không có chữ ký hợp lệ, middleware sẽ tự động trả về HTTP response 403:
Route::post('/unsubscribe/{user}', function (Request $request) {
// ...
})->name('unsubscribe')->middleware('signed');
Nếu trong signed URL của bạn không chứa tên miền trong URL hash, bạn nên cung cấp tham số relative cho middleware:
Route::post('/unsubscribe/{user}', function (Request $request) {
// ...
})->name('unsubscribe')->middleware('signed:relative');
Khi ai đó truy cập một URL signed đã hết hạn, họ sẽ nhận được một trang lỗi chung có mã trạng thái HTTP 403. Tuy nhiên, bạn có thể tùy chỉnh hành vi này bằng cách định nghĩa một closure "render" tùy chỉnh cho exception InvalidSignatureException trong file bootstrap/app.php của ứng dụng của bạn:
use Illuminate\Routing\Exceptions\InvalidSignatureException;
->withExceptions(function (Exceptions $exceptions) {
$exceptions->render(function (InvalidSignatureException $e) {
return response()->view('errors.link-expired', status: 403);
});
})
Hàm action giúp tạo ra một URL cho một controller action:
use App\Http\Controllers\HomeController;
$url = action([HomeController::class, 'index']);
Nếu phương thức controller yêu cầu truyền một route parameter, bạn có thể truyền một mảng các tham số route làm tham số thứ hai cho hàm như sau:
$url = action([UserController::class, 'profile'], ['id' => 1]);
Class Uri của Laravel cung cấp một interface tiện lợi và rõ ràng để tạo và thao tác với các URI thông qua các đối tượng. Class này chứa các chức năng được cung cấp bởi package League URI và tích hợp mượt mà với hệ thống routing của Laravel.
Bạn có thể tạo một instance Uri dễ dàng bằng các phương thức static:
use App\Http\Controllers\UserController;
use App\Http\Controllers\InvokableController;
use Illuminate\Support\Uri;
// Generate a URI instance from the given string...
$uri = Uri::of('https://example.com/path');
// Generate URI instances to paths, named routes, or controller actions...
$uri = Uri::to('/dashboard');
$uri = Uri::route('users.show', ['user' => 1]);
$uri = Uri::signedRoute('users.show', ['user' => 1]);
$uri = Uri::temporarySignedRoute('user.index', now()->plus(minutes: 5));
$uri = Uri::action([UserController::class, 'index']);
$uri = Uri::action(InvokableController::class);
// Generate a URI instance from the current request URL...
$uri = $request->uri();
// Generate a URI instance from the previous request URL...
$uri = $request->session()->previousUri();
Once you have a URI instance, you can fluently modify it:
$uri = Uri::of('https://example.com')
->withScheme('http')
->withHost('test.com')
->withPort(8000)
->withPath('/users')
->withQuery(['page' => 2])
->withFragment('section-1');
For more information on working with fluent URI objects, consult the URI documentation.
Đối với một số application, bạn có thể muốn định nghĩa các giá trị mặc định cho các tham số URL trong toàn bộ request. Ví dụ: hãy tưởng tượng nhiều route của bạn định nghĩa tham số {locale}:
Route::get('/{locale}/posts', function () {
// ...
})->name('post.index');
Sẽ thật là cồng kềnh khi luôn luôn phải truyền một tham số locale mỗi khi bạn gọi helper route. Vì vậy, bạn có thể sử dụng phương thức URL::defaults để định nghĩa một giá trị mặc định cho tham số này và lúc nào cũng được áp dụng trong request hiện tại. Bạn có thể muốn gọi phương thức này từ route middleware để bạn có quyền truy cập vào request hiện tại:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\URL;
use Symfony\Component\HttpFoundation\Response;
class SetDefaultLocaleForUrls
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
URL::defaults(['locale' => $request->user()->locale]);
return $next($request);
}
}
Khi giá trị mặc định cho tham số locale đã được cài đặt, bạn sẽ không cần phải truyền giá trị của nó khi tạo URL thông qua helper route.
Việc set giá trị mặc định của URL có thể cản trở việc xử lý các liên kết ngầm model của Laravel. Do đó, bạn nên ưu tiên middleware của bạn về set mặc định URL được chạy trước middleware SubstituteBindings của Laravel. Bạn có thể thực hiện điều này bằng cách sử dụng phương thức priority middleware method trong file bootstrap/app.php của ứng dụng của bạn:
->withMiddleware(function (Middleware $middleware): void {
$middleware->prependToPriorityList(
before: \Illuminate\Routing\Middleware\SubstituteBindings::class,
prepend: \App\Http\Middleware\SetDefaultLocaleForUrls::class,
);
})
entry