什么是响应
控制器或路由必须向用户的浏览器返回某种响应。
Laravel 提供了简单的机制来返回字符串、数组、视图、重定向、JSON 等多种形式的响应。
基本响应
返回字符串
最简单的响应就是直接返回字符串。
Laravel 会自动将其转为合适的 HTTP 响应。
Route::get('/', function () {
return 'Hello World';
});
返回数组
若返回数组,Laravel 会自动将其转换为 JSON 格式响应。
Route::get('/users', function () {
return [
['id' => 1, 'name' => '田中'],
['id' => 2, 'name' => '铃木'],
];
});
直接返回 Eloquent 模型或集合也会自动转换为 JSON 格式。这是一种非常方便构建 API 的常见模式。
返回 Eloquent 模型
use App\Models\User;
Route::get('/user/{user}', function (User $user) {
return $user;
});
Response 对象
使用 response() 辅助函数可以返回带有 HTTP 状态码、请求头等详细信息的响应。
Route::get('/home', function () {
return response('Hello World', 200)
->header('Content-Type', 'text/plain');
});
response() 的第一个参数是响应体,第二个参数是 HTTP 状态码。
常用 HTTP 状态码
| 状态码 | 含义 |
|---|
200 | OK(成功) |
201 | Created(资源创建成功) |
204 | No Content(无内容) |
301 | Moved Permanently(永久重定向) |
302 | Found(临时重定向) |
404 | Not Found(未找到) |
422 | Unprocessable Entity(校验错误) |
500 | Internal Server Error(服务器错误) |
视图响应
要从控制器返回 Blade 模板,请使用 view()。
这是 Web 应用中最常见的响应类型。
<?php
namespace App\Http\Controllers;
use Illuminate\View\View;
class HomeController extends Controller
{
public function index(): View
{
$users = [
['name' => '田中', 'email' => '[email protected]'],
['name' => '铃木', 'email' => '[email protected]'],
];
return view('users.index', ['users' => $users]);
}
}
view() 的第一个参数是视图名,第二个参数是要传给视图的数据数组。
为返回值类型指定 Illuminate\View\View 可以让代码意图更清晰。
使用 response()->view() 进行细粒度控制
若需要同时指定状态码和请求头,可使用 response()->view()。
return response()
->view('errors.404', ['message' => '页面未找到'], 404);
重定向
基本重定向
redirect() 辅助函数会返回重定向响应。
表单提交后跳转到另一个页面时经常使用。
use Illuminate\Http\RedirectResponse;
Route::get('/old-page', function (): RedirectResponse {
return redirect('/new-page');
});
在控制器中的用法:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class PostController extends Controller
{
public function store(Request $request): RedirectResponse
{
// 保存文章的处理...
return redirect('/posts');
}
}
重定向到命名路由
使用 route() 函数可以不直接写 URL,而通过路由名指定跳转目标。
即使 URL 发生变化也无需修改代码,因此推荐使用命名路由。
// 给路由命名
Route::get('/posts', [PostController::class, 'index'])->name('posts.index');
Route::get('/posts/{post}', [PostController::class, 'show'])->name('posts.show');
// 重定向到命名路由
return redirect()->route('posts.index');
// 传入路由参数
return redirect()->route('posts.show', ['post' => $post->id]);
返回上一页
back() 让用户返回上一个页面,常用于校验失败后的重定向。
return back();
// 保留输入数据后返回
return back()->withInput();
带闪存消息的重定向
使用 with() 可以在 Session 中附带一条消息进行重定向。
适合表单提交成功后的提示。
return redirect('/posts')->with('success', '文章已创建。');
在 Blade 模板中显示消息。
@if (session('success'))
<div class="alert alert-success">
{{ session('success') }}
</div>
@endif
JSON 响应
构建 API 时,使用 response()->json() 返回 JSON 响应。
它会自动设置 Content-Type: application/json 头。
use Illuminate\Http\JsonResponse;
Route::get('/api/users', function (): JsonResponse {
$users = [
['id' => 1, 'name' => '田中'],
['id' => 2, 'name' => '铃木'],
];
return response()->json($users);
});
也可以指定状态码。
return response()->json(['message' => '已创建'], 201);
在控制器中的用法:
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class UserController extends Controller
{
public function index(): JsonResponse
{
$users = User::all();
return response()->json($users);
}
public function store(Request $request): JsonResponse
{
// 使用校验过的数据创建(在 Form Request 或 $request->validate() 之后)
$user = User::create($request->validated());
return response()->json($user, 201);
}
}
直接返回数组或 Eloquent 模型也会得到 JSON 响应,但 response()->json() 能更细致地控制状态码与请求头。
响应头
使用 header() 方法可以向响应添加 HTTP 头。
return response('Hello World')
->header('Content-Type', 'text/plain')
->header('X-Custom-Header', 'MyValue');
若要一次设置多个响应头,可以使用 withHeaders()。
return response('Hello World')
->withHeaders([
'Content-Type' => 'text/plain',
'X-Custom-Header' => 'MyValue',
'Cache-Control' => 'no-cache',
]);
实践示例:控制器中的用法差异
下面是根据用途区分响应的示例。
定义路由
use App\Http\Controllers\PostController;
Route::get('/posts', [PostController::class, 'index'])->name('posts.index');
Route::get('/posts/create', [PostController::class, 'create'])->name('posts.create');
Route::post('/posts', [PostController::class, 'store'])->name('posts.store');
Route::get('/posts/{post}', [PostController::class, 'show'])->name('posts.show');
Route::delete('/posts/{post}', [PostController::class, 'destroy'])->name('posts.destroy');
实现控制器
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
class PostController extends Controller
{
// 列表:返回视图
public function index(): View
{
$posts = Post::latest()->get();
return view('posts.index', ['posts' => $posts]);
}
// 创建表单:返回视图
public function create(): View
{
return view('posts.create');
}
// 保存:返回重定向
public function store(Request $request): RedirectResponse
{
// 使用校验过的数据创建(如果使用了 Form Request)
$post = Post::create($request->validated());
return redirect()
->route('posts.show', ['post' => $post->id])
->with('success', '文章已创建。');
}
// 详情:返回视图
public function show(Post $post): View
{
return view('posts.show', ['post' => $post]);
}
// 删除:返回重定向
public function destroy(Post $post): RedirectResponse
{
$post->delete();
return redirect()
->route('posts.index')
->with('success', '文章已删除。');
}
}
在 Web 应用中,最基本的模式就是区分 View 与 RedirectResponse。展示型的动作返回 View;创建、更新、删除等修改型动作在处理完成后返回 RedirectResponse。
下一步
校验
在返回响应之前,学习如何通过校验来验证输入数据。