> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# 响应

> 介绍 Laravel 中的各种响应类型，以及如何在控制器中返回合适的响应。

## 什么是响应

控制器或路由必须向用户的浏览器返回某种**响应**。
Laravel 提供了简单的机制来返回字符串、数组、视图、重定向、JSON 等多种形式的响应。

## 基本响应

### 返回字符串

最简单的响应就是直接返回字符串。
Laravel 会自动将其转为合适的 HTTP 响应。

```php theme={null}
Route::get('/', function () {
    return 'Hello World';
});
```

### 返回数组

若返回数组，Laravel 会自动将其转换为 JSON 格式响应。

```php theme={null}
Route::get('/users', function () {
    return [
        ['id' => 1, 'name' => '田中'],
        ['id' => 2, 'name' => '铃木'],
    ];
});
```

<Info>
  直接返回 Eloquent 模型或集合也会自动转换为 JSON 格式。这是一种非常方便构建 API 的常见模式。
</Info>

### 返回 Eloquent 模型

```php theme={null}
use App\Models\User;

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

## Response 对象

使用 `response()` 辅助函数可以返回带有 HTTP 状态码、请求头等详细信息的响应。

```php theme={null}
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 theme={null}
<?php

namespace App\Http\Controllers;

use Illuminate\View\View;

class HomeController extends Controller
{
    public function index(): View
    {
        $users = [
            ['name' => '田中', 'email' => 'tanaka@example.com'],
            ['name' => '铃木', 'email' => 'suzuki@example.com'],
        ];

        return view('users.index', ['users' => $users]);
    }
}
```

`view()` 的第一个参数是视图名，第二个参数是要传给视图的数据数组。

<Tip>
  为返回值类型指定 `Illuminate\View\View` 可以让代码意图更清晰。
</Tip>

### 使用 `response()->view()` 进行细粒度控制

若需要同时指定状态码和请求头，可使用 `response()->view()`。

```php theme={null}
return response()
    ->view('errors.404', ['message' => '页面未找到'], 404);
```

## 重定向

### 基本重定向

`redirect()` 辅助函数会返回重定向响应。
表单提交后跳转到另一个页面时经常使用。

```php theme={null}
use Illuminate\Http\RedirectResponse;

Route::get('/old-page', function (): RedirectResponse {
    return redirect('/new-page');
});
```

在控制器中的用法：

```php theme={null}
<?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 发生变化也无需修改代码，因此推荐使用命名路由。

```php theme={null}
// 给路由命名
Route::get('/posts', [PostController::class, 'index'])->name('posts.index');
Route::get('/posts/{post}', [PostController::class, 'show'])->name('posts.show');
```

```php theme={null}
// 重定向到命名路由
return redirect()->route('posts.index');

// 传入路由参数
return redirect()->route('posts.show', ['post' => $post->id]);
```

### 返回上一页

`back()` 让用户返回上一个页面，常用于校验失败后的重定向。

```php theme={null}
return back();

// 保留输入数据后返回
return back()->withInput();
```

### 带闪存消息的重定向

使用 `with()` 可以在 Session 中附带一条消息进行重定向。
适合表单提交成功后的提示。

```php theme={null}
return redirect('/posts')->with('success', '文章已创建。');
```

在 Blade 模板中显示消息。

```blade theme={null}
@if (session('success'))
    <div class="alert alert-success">
        {{ session('success') }}
    </div>
@endif
```

## JSON 响应

构建 API 时，使用 `response()->json()` 返回 JSON 响应。
它会自动设置 `Content-Type: application/json` 头。

```php theme={null}
use Illuminate\Http\JsonResponse;

Route::get('/api/users', function (): JsonResponse {
    $users = [
        ['id' => 1, 'name' => '田中'],
        ['id' => 2, 'name' => '铃木'],
    ];

    return response()->json($users);
});
```

也可以指定状态码。

```php theme={null}
return response()->json(['message' => '已创建'], 201);
```

在控制器中的用法：

```php theme={null}
<?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);
    }
}
```

<Info>
  直接返回数组或 Eloquent 模型也会得到 JSON 响应，但 `response()->json()` 能更细致地控制状态码与请求头。
</Info>

## 响应头

使用 `header()` 方法可以向响应添加 HTTP 头。

```php theme={null}
return response('Hello World')
    ->header('Content-Type', 'text/plain')
    ->header('X-Custom-Header', 'MyValue');
```

若要一次设置多个响应头，可以使用 `withHeaders()`。

```php theme={null}
return response('Hello World')
    ->withHeaders([
        'Content-Type' => 'text/plain',
        'X-Custom-Header' => 'MyValue',
        'Cache-Control' => 'no-cache',
    ]);
```

## 实践示例：控制器中的用法差异

下面是根据用途区分响应的示例。

<Steps>
  <Step title="定义路由">
    ```php theme={null}
    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');
    ```
  </Step>

  <Step title="实现控制器">
    ```php theme={null}
    <?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', '文章已删除。');
        }
    }
    ```
  </Step>
</Steps>

<Tip>
  在 Web 应用中，最基本的模式就是区分 `View` 与 `RedirectResponse`。展示型的动作返回 `View`；创建、更新、删除等修改型动作在处理完成后返回 `RedirectResponse`。
</Tip>

## 下一步

<Card title="校验" icon="check-circle" href="/zh/validation">
  在返回响应之前，学习如何通过校验来验证输入数据。
</Card>


## Related topics

- [⚡ Livewire 4 入门 —— 无需 JavaScript 也能做出响应式 UI](/zh/blog/livewire-introduction.md)
- [请求生命周期](/zh/lifecycle.md)
- [HTTP 客户端](/zh/http-client.md)
- [Laravel AI SDK](/zh/ai-sdk.md)
- [Vue.js 入门 —— 与 Inertia × Laravel 搭配使用的基础](/zh/blog/vue-introduction.md)
