生成 URL 简介 Laravel 提供了几个辅助函数来为应用程序生成 URL。主要用于在模板和 API 响应中构建 URL 或者在应用程序的其它部分生成重定向响应。 基础 生成基础 URL 辅助函数 url 可以用于应用的任何一个 URL。生成的 URL 将自动使用当前请求中的方案 (HTTP or HTTPS) 和主机: ``` $post = App\Models\Post::find(1); echo url("/posts/{$post->id}"); // http://example.com/posts/1 访问当前 URL 如果没有给辅助函数 url 提供路径,则会返回一个 Illuminate\Routing\UrlGenerator 实例,来允许你访问有关当前 URL 的信息: // 获取当前 URL 没有 query string... echo url()->current(); // 获取当前 URL 包括 query string... echo url()->full(); // 获取上个请求 URL echo url()->previous(); ``` 上面的这些方法都可以通过 URL facade 访问: ``` use Illuminate\Support\Facades\URL; echo URL::current(); ``` 命名路由的 URL 辅助函数 route 可以用于为指定路由生成 URL。命名路由生成的 URL 不与路由上定义的 URL 相耦合。因此,就算路由的 URL 有任何改变,都不需要对 route 函数调用进行任何更改。例如,假设你的应用程序包含以下路由: ``` Route::get('/post/{post}', function () { // })->name('post.show'); ``` 要生成此路由的 URL ,可以像这样使用辅助函数 route : ``` echo route('post.show', ['post' => 1]); // http://example.com/post/1 ``` 您通常会使用 Eloquent 模型 的主键生成 URL。因此,您可以将 Eloquent 模型作为参数值传递。route 辅助函数将自动提取模型的主键: ``` echo route('post.show', ['post' => $post]); ``` 辅助函数 route 也可用于为具有多个参数的路由生成 URL: ``` 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 ``` 签名 URL Laravel 允许你轻松地为命名路径创建「签名」URL,这些 URL 在查询字符串后附加了「签名」哈希,允许 Laravel 验证 URL 自创建以来未被修改过。签名 URL 对于可公开访问但需要一层防止 URL 操作的路由特别有用。 例如,你可以使用签名 URL 来实现通过电子邮件发送给客户的公共「取消订阅」链接。要创建指向路径的签名 URL ,请使用 URL facade 的 signedRoute 方法: ``` use Illuminate\Support\Facades\URL; return URL::signedRoute('unsubscribe', ['user' => 1]); ``` 如果要生成具有有效期的临时签名路由 URL,可以使用以下 temporarySignedRoute 方法: ``` use Illuminate\Support\Facades\URL; return URL::temporarySignedRoute( 'unsubscribe', now()->addMinutes(30), ['user' => 1] ); ``` 验证签名路由请求 要验证传入请求是否具有有效签名,你应该对传入的 Request 调用 hasValidSignature 方法: ``` use Illuminate\Http\Request; Route::get('/unsubscribe/{user}', function (Request $request) { if (! $request->hasValidSignature()) { abort(401); } // ... })->name('unsubscribe'); ``` 或者,你可以将 Illuminate\Routing\Middleware\ValidateSignature 中间件分配给路由。如果它不存在,则应该在 HTTP 内核的 routeMiddleware 数组中为此中间件分配一个键: ``` /** * 路由中间件 * * 这些中间件可以分配给组,也可以单独使用 * * @var array */ protected $routeMiddleware = [ 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class, ]; ``` 在内核中注册中间件后,你可以将其附加到路由中。如果传入请求没有有效签名,则中间件将自动返回 403 错误响应: ``` Route::post('/unsubscribe/{user}', function (Request $request) { // ... })->name('unsubscribe')->middleware('signed'); ``` 控制器行为的 URL action 功能可以为给定的控制器行为生成 URL。 ``` use App\Http\Controllers\HomeController; $url = action([HomeController::class, 'index']); ``` 如果控制器方法接收路由参数,你可以通过第二个参数传递: ``` $url = action([UserController::class, 'profile'], ['id' => 1]); ``` 默认值 对于某些应用程序,你可能希望为某些 URL 参数的请求范围指定默认值。例如,假设有些路由定义了 {locale} 参数: ``` Route::get('/{locale}/posts', function () { // })->name('post.index'); ``` 每次都通过 locale 来调用辅助函数 route 也是一件很麻烦的事情。 因此,使用 URL::defaults 方法定义这个参数的默认值,可以让该参数始终存在当前请求中。然后就能从 路由中间件 调用此方法来访问当前请求: ``` <?php namespace App\Http\Middleware; use Closure; use Illuminate\Support\Facades\URL; class SetDefaultLocaleForUrls { public function handle($request, Closure $next) { URL::defaults(['locale' => $request->user()->locale]); return $next($request); } } ``` 一旦设置了 locale 参数的默认值,您就不再需要通过辅助函数 route 生成 URL 时传递它的值。 ``` URL Defaults & Middleware Priority Setting URL default values can interfere with Laravel’s handling of implicit model bindings. Therefore, you should prioritize your middleware that set URL defaults to be executed before Laravel’s own SubstituteBindings middleware. You can accomplish this by making sure your middleware occurs before the SubstituteBindings middleware within the $middlewarePriority property of your application’s HTTP kernel. The $middlewarePriority property is defined in the base Illuminate\Foundation\Http\Kernel class. You may copy its definition from that class and overwrite it in your application’s HTTP kernel in order to modify it: /** * The priority-sorted list of middleware. * * This forces non-global middleware to always be in the given order. * * @var array */ protected $middlewarePriority = [ // ... \App\Http\Middleware\SetDefaultLocaleForUrls::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, // ... ]; ```