Laravel 13 响应处理详解
响应是 Web 应用与客户端交互的核心。本文将深入探讨 Laravel 13 中各种响应类型和高级用法。
基础响应
字符串响应
1 2 3 4 5 6 7 8
| Route::get('/', function () { return 'Hello World'; });
Route::get('/', function () { return response('Hello World', 200) ->header('Content-Type', 'text/plain'); });
|
数组与集合响应
1 2 3 4 5 6 7
| Route::get('/users', function () { return [1, 2, 3]; });
Route::get('/users', function () { return User::all(); });
|
JSON 响应
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| use Illuminate\Http\JsonResponse;
Route::get('/user', function () { return response()->json([ 'name' => 'John', 'email' => 'john@example.com', ]); });
Route::get('/user', function () { return response()->json(['name' => 'John']) ->withCallback(request()->input('callback')); });
Route::get('/users', function () { return User::all()->toJson(); });
|
响应对象
创建响应
1 2 3 4 5 6 7 8 9 10 11 12 13
| use Illuminate\Http\Response;
$response = new Response('Content', 200);
$response = response('Content', 200) ->header('Content-Type', 'text/html') ->header('X-Custom-Header', 'value');
$response = response('Content') ->withHeaders([ 'Content-Type' => 'text/html', 'X-Custom-Header' => 'value', ]);
|
设置 Cookie
1 2 3 4 5 6 7 8 9
| $response = response('Hello') ->cookie('name', 'value', $minutes) ->cookie('name', 'value', $minutes, $path, $domain, $secure, $httpOnly);
$response = response('Hello') ->cookie(cookie('name', 'value', $minutes));
$response = response('Hello') ->withoutCookie('name');
|
视图响应
返回视图
1 2 3 4 5 6 7 8 9 10 11 12 13
| Route::get('/', function () { return view('home'); });
Route::get('/', function () { return view('home', ['name' => 'John']); });
Route::get('/', function () { return response() ->view('home', ['name' => 'John']) ->header('X-Custom', 'value'); });
|
视图响应状态码
1 2
| return response()->view('errors.404', [], 404); return response()->view('errors.500', [], 500);
|
JSON 响应高级用法
JSONP 响应
1 2 3
| return response() ->json(['name' => 'John']) ->withCallback(request()->input('callback'));
|
分页 JSON 响应
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| Route::get('/users', function () { $users = User::paginate(15);
return response()->json([ 'success' => true, 'data' => $users->items(), 'meta' => [ 'current_page' => $users->currentPage(), 'last_page' => $users->lastPage(), 'per_page' => $users->perPage(), 'total' => $users->total(), ], 'links' => [ 'first' => $users->url(1), 'last' => $users->url($users->lastPage()), 'prev' => $users->previousPageUrl(), 'next' => $users->nextPageUrl(), ], ]); });
|
条件 JSON 响应
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| Route::get('/user/{id}', function ($id) { $user = User::find($id);
if (!$user) { return response()->json([ 'success' => false, 'message' => '用户不存在', ], 404); }
return response()->json([ 'success' => true, 'data' => $user, ]); });
|
文件响应
文件下载
1 2 3 4 5 6 7 8 9 10 11
| Route::get('/download', function () { return response()->download($pathToFile); });
Route::get('/download', function () { return response()->download($pathToFile, $name, $headers); });
Route::get('/download', function () { return response()->download($pathToFile)->deleteFileAfterSend(); });
|
流式下载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| Route::get('/export', function () { return response()->streamDownload(function () { echo 'CSV内容...'; }, 'export.csv'); });
Route::get('/export', function () { $content = 'name,email' . PHP_EOL; $content .= 'John,john@example.com' . PHP_EOL;
return response()->streamDownload(function () use ($content) { echo $content; }, 'users.csv', [ 'Content-Type' => 'text/csv', ]); });
|
文件显示
1 2 3 4 5 6 7
| Route::get('/file', function () { return response()->file($pathToFile); });
Route::get('/file', function () { return response()->file($pathToFile, $headers); });
|
流式响应
基础流式响应
1 2 3 4 5 6 7 8 9 10 11 12 13
| Route::get('/stream', function () { return response()->stream(function () { for ($i = 0; $i < 10; $i++) { echo "数据行 {$i}\n"; flush(); sleep(1); } }, 200, [ 'Content-Type' => 'text/plain', 'Cache-Control' => 'no-cache', 'X-Accel-Buffering' => 'no', ]); });
|
SSE 流式响应
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| Route::get('/events', function () { return response()->stream(function () { while (true) { $data = json_encode([ 'time' => now()->toIso8601String(), 'message' => 'Hello', ]);
echo "data: {$data}\n\n";
if (ob_get_level() > 0) { ob_flush(); }
flush();
if (connection_aborted()) { break; }
sleep(1); } }, 200, [ 'Content-Type' => 'text/event-stream', 'Cache-Control' => 'no-cache', 'Connection' => 'keep-alive', 'X-Accel-Buffering' => 'no', ]); });
|
大文件流式导出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| Route::get('/export-large', function () { return response()->stream(function () { $handle = fopen('php://output', 'w');
fputcsv($handle, ['ID', 'Name', 'Email']);
User::chunk(1000, function ($users) use ($handle) { foreach ($users as $user) { fputcsv($handle, [$user->id, $user->name, $user->email]); } });
fclose($handle); }, 200, [ 'Content-Type' => 'text/csv', 'Content-Disposition' => 'attachment; filename="users.csv"', ]); });
|
重定向响应
基础重定向
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| Route::get('/redirect', function () { return redirect('/home'); });
Route::get('/redirect', function () { return redirect()->route('home'); });
Route::get('/redirect', function () { return redirect()->action([HomeController::class, 'index']); });
Route::get('/redirect', function () { return redirect()->back(); });
Route::get('/redirect', function () { return redirect()->back()->withInput(); });
|
带参数重定向
1 2 3 4 5 6 7
| Route::get('/redirect', function () { return redirect()->route('user.profile', ['id' => 1]); });
Route::get('/redirect', function () { return redirect()->away('https://example.com'); });
|
闪存数据重定向
1 2 3 4 5 6 7 8 9 10 11 12 13
| Route::post('/user', function () { return redirect('home')->with('status', '用户创建成功'); });
Route::post('/user', function () { return redirect('home')->withErrors(['name' => '名称不能为空']); });
Route::post('/user', function () { return redirect('home') ->withInput() ->withErrors(['name' => '名称不能为空']); });
|
API 资源响应
资源类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| <?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource { public function toArray($request): array { return [ 'id' => $this->id, 'name' => $this->name, 'email' => $this->email, 'created_at' => $this->created_at->toISOString(), 'links' => [ 'self' => route('users.show', $this->id), ], ]; }
public function with($request): array { return [ 'meta' => [ 'version' => '1.0', ], ]; }
public function withResponse($request, $response): void { $response->header('X-Resource', 'User'); } }
|
资源集合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class UserCollection extends ResourceCollection { public function toArray($request): array { return [ 'data' => $this->collection, 'meta' => [ 'total' => $this->total(), 'count' => $this->count(), 'per_page' => $this->perPage(), 'current_page' => $this->currentPage(), 'total_pages' => $this->lastPage(), ], 'links' => [ 'self' => $this->url($this->currentPage()), 'first' => $this->url(1), 'last' => $this->url($this->lastPage()), 'prev' => $this->previousPageUrl(), 'next' => $this->nextPageUrl(), ], ]; } }
|
使用资源
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| use App\Http\Resources\UserResource; use App\Http\Resources\UserCollection;
Route::get('/user/{id}', function ($id) { return new UserResource(User::findOrFail($id)); });
Route::get('/users', function () { return new UserCollection(User::paginate()); });
Route::get('/users', function () { return UserResource::collection(User::all()); });
|
响应宏
定义响应宏
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| <?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\Facades\Response;
class ResponseMacroServiceProvider extends ServiceProvider { public function boot(): void { Response::macro('success', function ($data = null, string $message = '', int $code = 200) { return Response::json([ 'success' => true, 'data' => $data, 'message' => $message, ], $code); });
Response::macro('error', function (string $message, int $code = 400, $errors = null) { return Response::json([ 'success' => false, 'message' => $message, 'errors' => $errors, ], $code); });
Response::macro('paginated', function ($paginator, string $resourceClass) { return Response::json([ 'success' => true, 'data' => $resourceClass::collection($paginator->items()), 'meta' => [ 'current_page' => $paginator->currentPage(), 'last_page' => $paginator->lastPage(), 'per_page' => $paginator->perPage(), 'total' => $paginator->total(), ], ]); });
Response::macro('csv', function ($data, string $filename = 'export.csv') { $handle = fopen('php://temp', 'r+');
foreach ($data as $row) { fputcsv($handle, $row); }
rewind($handle); $content = stream_get_contents($handle); fclose($handle);
return Response::make($content, 200, [ 'Content-Type' => 'text/csv', 'Content-Disposition' => 'attachment; filename="' . $filename . '"', ]); }); } }
|
使用响应宏
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| Route::get('/success', function () { return response()->success(['name' => 'John'], '操作成功'); });
Route::get('/error', function () { return response()->error('操作失败', 400, ['name' => '名称不能为空']); });
Route::get('/users', function () { return response()->paginated(User::paginate(), UserResource::class); });
Route::get('/export', function () { $data = [ ['ID', 'Name', 'Email'], [1, 'John', 'john@example.com'], [2, 'Jane', 'jane@example.com'], ];
return response()->csv($data, 'users.csv'); });
|
响应中间件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <?php
namespace App\Http\Middleware;
use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response;
class AddSecurityHeaders { public function handle(Request $request, Closure $next): Response { $response = $next($request);
$response->headers->set('X-Content-Type-Options', 'nosniff'); $response->headers->set('X-Frame-Options', 'SAMEORIGIN'); $response->headers->set('X-XSS-Protection', '1; mode=block');
if ($request->isSecure()) { $response->headers->set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains'); }
return $response; } }
|
总结
Laravel 13 的响应处理提供了:
- 多种响应类型支持
- JSON 和 JSONP 响应
- 文件下载和流式响应
- SSE 服务器推送事件
- 灵活的重定向
- API 资源转换
- 可扩展的响应宏
掌握响应处理技巧可以构建更加灵活和高效的 API 接口。