Laravel 11 响应类型与自定义

在 Laravel 中,路由或控制器最终需要返回一个响应对象,将内容发送给客户端。框架提供了丰富的响应类型和灵活的定制方式,让你能够轻松构建各种 HTTP 响应。 本章将系统介绍常见的响应类型以及如何自定义响应行为。

📤 响应基础

在 Laravel 中,最简单的响应是返回字符串或数组,框架会自动转换为合适的响应对象:

Route::get('/', function () {
    return 'Hello, World!';  // 返回字符串,响应类型为 text/html
});

Route::get('/data', function () {
    return ['name' => 'John', 'age' => 30];  // 返回数组,自动转为 JSON
});
💡 提示: 返回数组时,Laravel 会自动将 Content-Type 设置为 application/json 并返回 JSON 格式。

🎯 常用响应类型

1. 视图响应

通过 view() 辅助函数返回 Blade 视图:

return view('welcome', ['name' => 'Taylor']);
2. JSON 响应

使用 response()->json() 可以更精确地控制 JSON 响应:

return response()->json([
    'name' => 'Abigail',
    'state' => 'CA'
], 201, ['X-Header' => 'value']);

也可以设置 JSON 响应选项,如 JSON_PRETTY_PRINT:

return response()->json($data, 200, [], JSON_PRETTY_PRINT);
3. 重定向响应

重定向响应有多种生成方式:

// 重定向到指定 URL
return redirect('/dashboard');

// 重定向到路由名称
return redirect()->route('profile');

// 重定向到带有参数的命名路由
return redirect()->route('profile', ['id' => 1]);

// 重定向回上一页
return redirect()->back();

// 重定向并携带闪存数据
return redirect()->route('login')->with('error', '登录失败');

// 重定向到控制器动作
return redirect()->action([UserController::class, 'index']);
4. 文件下载响应

使用 download 方法让浏览器下载文件:

return response()->download($pathToFile);  // 使用原文件名
return response()->download($pathToFile, 'custom_name.pdf');  // 自定义文件名
return response()->download($pathToFile, 'custom.pdf', ['Content-Type' => 'application/pdf']);
5. 文件响应(内联)

使用 file 方法在浏览器中直接显示文件(如图片、PDF):

return response()->file($pathToFile);
return response()->file($pathToFile, ['Content-Type' => 'image/jpeg']);
6. 无内容响应

返回一个没有内容的响应,常用于删除等操作:

return response()->noContent();  // 状态码 204
7. 流式响应

对于大文件或流式数据,可以使用 stream 方法:

return response()->stream(function () {
    echo 'Hello, ';
    echo 'World!';
}, 200, ['Content-Type' => 'text/plain']);

🔧 响应工厂与响应实例

所有响应类型都可以通过 response() 辅助函数获得响应工厂实例,然后调用对应方法:

  • response()->view('view.name', $data) → 视图响应
  • response()->json($data, $status, $headers) → JSON 响应
  • response()->redirectTo($url) → 重定向响应
  • response()->download($path, $name, $headers) → 下载响应
  • response()->file($path, $headers) → 文件响应
  • response()->noContent($status) → 无内容响应
💡 提示: 你也可以直接创建 Illuminate\Http\ResponseIlluminate\Http\JsonResponse 实例,但使用工厂方法更为简洁。

🧩 自定义响应宏

如果某些响应模式在项目中频繁使用,可以通过响应宏扩展响应工厂。在服务提供者(如 AppServiceProvider)的 boot 方法中注册:

use Illuminate\Support\Facades\Response;

public function boot(): void
{
    Response::macro('success', function ($message, $data = null, $status = 200) {
        return response()->json([
            'success' => true,
            'message' => $message,
            'data'    => $data,
        ], $status);
    });

    Response::macro('error', function ($message, $code = 400, $errors = []) {
        return response()->json([
            'success' => false,
            'message' => $message,
            'errors'  => $errors,
        ], $code);
    });
}

之后可以在控制器中直接使用:

return response()->success('用户创建成功', $user, 201);
return response()->error('参数错误', 422, ['email' => '邮箱格式不正确']);

📦 自定义响应类

对于更复杂的响应逻辑,可以创建自定义响应类,继承 Illuminate\Http\ResponseIlluminate\Http\JsonResponse

namespace App\Http\Responses;

use Illuminate\Http\JsonResponse;

class ApiResponse extends JsonResponse
{
    public function __construct($data = null, $message = 'Success', $status = 200, $headers = [], $options = 0)
    {
        $payload = [
            'status'  => $status,
            'message' => $message,
            'data'    => $data,
        ];
        parent::__construct($payload, $status, $headers, $options);
    }

    public static function error($message, $status = 400, $errors = [])
    {
        $payload = [
            'status'  => $status,
            'message' => $message,
            'errors'  => $errors,
        ];
        return new static($payload, $status);
    }
}

使用时:

return new ApiResponse($user, '获取成功');
return ApiResponse::error('未找到资源', 404);

🎨 实战示例:统一的 API 响应格式

以下是一个完整的示例,展示如何使用响应宏实现统一的 API 响应格式:

服务提供者注册(AppServiceProvider):

use Illuminate\Support\Facades\Response;

public function boot(): void
{
    Response::macro('api', function ($data = null, $message = null, $code = 200) {
        return response()->json([
            'code'    => $code,
            'message' => $message ?? ($code === 200 ? 'Success' : 'Error'),
            'data'    => $data,
        ], $code);
    });
}

控制器中使用:

public function index()
{
    $users = User::all();
    return response()->api($users, '用户列表获取成功');
}

public function store(Request $request)
{
    // 验证...
    $user = User::create($request->all());
    return response()->api($user, '用户创建成功', 201);
}

public function show($id)
{
    $user = User::find($id);
    if (!$user) {
        return response()->api(null, '用户不存在', 404);
    }
    return response()->api($user);
}

⚠️ 响应头与 Cookies

可以在响应中添加自定义头部和 Cookies:

return response($content)
    ->header('X-Custom-Header', 'Value')
    ->withCookie(cookie('name', 'value', 60));  // 有效期 60 分钟

❓ 常见问题

使用 response() 工厂时,可以传递状态码作为第二个参数:response()->json($data, 201)。对于字符串响应,可以:response('Not Found', 404)

使用 with() 方法:return redirect()->route('profile')->with('status', '操作成功');,然后在视图中通过 session('status') 获取。

响应宏适合简单、通用的响应扩展;自定义响应类适合需要复杂逻辑或状态管理的场景。两者可以结合使用。

📝 小结

掌握 Laravel 的响应类型和自定义技巧,能够让你灵活应对各种前端需求,并保持代码的统一性和可维护性。 无论是简单的字符串、复杂的 JSON 还是文件下载,Laravel 都提供了优雅的解决方案。 结合响应宏和自定义响应类,可以进一步提升开发效率。 下一章我们将学习表单验证,为应用筑牢数据安全的第一道防线。