Laravel 13 HTTP 客户端详解
Laravel 的 HTTP 客户端基于 Guzzle,提供了流畅的 API 来发送 HTTP 请求。本文将深入探讨 Laravel 13 HTTP 客户端的高级用法。
基本请求
GET 请求
1 2 3 4 5 6 7 8
| use Illuminate\Support\Facades\Http;
$response = Http::get('https://api.example.com/users');
$response = Http::get('https://api.example.com/users', [ 'page' => 1, 'per_page' => 10, ]);
|
POST 请求
1 2 3 4 5 6 7 8 9
| $response = Http::post('https://api.example.com/users', [ 'name' => 'John Doe', 'email' => 'john@example.com', ]);
$response = Http::asForm()->post('https://api.example.com/login', [ 'email' => 'john@example.com', 'password' => 'password', ]);
|
其他 HTTP 方法
1 2 3 4 5
| Http::put('https://api.example.com/users/1', $data); Http::patch('https://api.example.com/users/1', $data); Http::delete('https://api.example.com/users/1'); Http::head('https://api.example.com/users/1'); Http::options('https://api.example.com/users');
|
请求头
设置请求头
1 2 3 4 5 6 7 8 9 10
| $response = Http::withHeaders([ 'Authorization' => 'Bearer token', 'X-Custom-Header' => 'value', ])->get('https://api.example.com/users');
$response = Http::withToken('token')->get('https://api.example.com/users');
$response = Http::withBasicAuth('username', 'password')->get('https://api.example.com/users');
$response = Http::withDigestAuth('username', 'password')->get('https://api.example.com/users');
|
User-Agent
1
| $response = Http::withUserAgent('MyApp/1.0')->get('https://api.example.com/users');
|
请求体
JSON 请求
1 2 3 4
| $response = Http::asJson()->post('https://api.example.com/users', $data);
$response = Http::post('https://api.example.com/users', $data);
|
表单请求
1 2 3 4
| $response = Http::asForm()->post('https://api.example.com/login', [ 'email' => 'john@example.com', 'password' => 'password', ]);
|
多部分请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| $response = Http::asMultipart()->post('https://api.example.com/upload', [ [ 'name' => 'file', 'contents' => fopen('/path/to/file', 'r'), 'filename' => 'document.pdf', ], [ 'name' => 'description', 'contents' => 'File description', ], ]);
$response = Http::attach( 'file', file_get_contents('/path/to/file'), 'document.pdf' )->post('https://api.example.com/upload');
|
响应处理
获取响应内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| $response = Http::get('https://api.example.com/users');
$body = $response->body(); $json = $response->json(); $object = $response->object(); $collection = $response->collect();
$status = $response->status(); $ok = $response->ok(); $successful = $response->successful(); $failed = $response->failed(); $clientError = $response->clientError(); $serverError = $response->serverError();
$headers = $response->headers(); $header = $response->header('Content-Type');
|
访问 JSON 数据
1 2 3 4 5
| $response = Http::get('https://api.example.com/users/1');
$name = $response->json('name'); $email = $response->json('contact.email'); $users = $response->json('data.*.name');
|
错误处理
异常处理
1 2 3 4 5 6 7 8 9 10
| use Illuminate\Http\Client\ConnectionException;
try { $response = Http::get('https://api.example.com/users'); $response->throw(); } catch (ConnectionException $e) { } catch (\Exception $e) { }
|
条件异常
1 2 3 4 5 6 7 8
| $response = Http::get('https://api.example.com/users');
if ($response->failed()) { $response->throw(); }
$response->throwIf($condition); $response->throwUnless($condition);
|
自定义异常
1 2 3 4 5 6 7 8
| $response = Http::get('https://api.example.com/users');
$response->throw(function ($response, $e) { Log::error('API request failed', [ 'status' => $response->status(), 'body' => $response->body(), ]); });
|
超时和重试
超时设置
1 2
| $response = Http::timeout(30)->get('https://api.example.com/users'); $response = Http::connectTimeout(10)->get('https://api.example.com/users');
|
重试机制
1 2 3 4 5 6 7
| $response = Http::retry(3, 100)->get('https://api.example.com/users');
$response = Http::retry(3, 100, function ($exception) { return $exception instanceof ConnectionException; })->get('https://api.example.com/users');
$response = Http::retry(3, 100, throw: false)->get('https://api.example.com/users');
|
并发请求
并行请求
1 2 3 4 5 6 7 8 9 10 11
| use Illuminate\Http\Client\Pool;
$responses = Http::pool(fn (Pool $pool) => [ $pool->as('users')->get('https://api.example.com/users'), $pool->as('posts')->get('https://api.example.com/posts'), $pool->as('comments')->get('https://api.example.com/comments'), ]);
$users = $responses['users']->json(); $posts = $responses['posts']->json(); $comments = $responses['comments']->json();
|
带配置的并发请求
1 2 3 4
| $responses = Http::pool(fn (Pool $pool) => [ $pool->as('users')->withToken('token')->get('https://api.example.com/users'), $pool->as('posts')->withToken('token')->get('https://api.example.com/posts'), ]);
|
宏请求
定义宏
1 2 3 4 5 6 7 8 9 10 11
| use Illuminate\Support\Facades\Http;
Http::macro('github', function () { return Http::withHeaders([ 'Authorization' => 'token ' . config('services.github.token'), 'Accept' => 'application/vnd.github.v3+json', ])->baseUrl('https://api.github.com'); });
$response = Http::github()->get('/repos/laravel/framework');
|
全局配置
全局请求头
1 2 3 4 5 6 7 8 9
| use Illuminate\Support\Facades\Http;
Http::globalOptions([ 'timeout' => 30, ]);
Http::globalHeaders([ 'X-App-Version' => '1.0', ]);
|
全局中间件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| use Illuminate\Support\Facades\Http; use Illuminate\Http\Client\Request;
Http::globalRequestMiddleware(function (Request $request) { $request->withHeader('X-Request-Id', Str::uuid()->toString()); return $request; });
Http::globalResponseMiddleware(function ($response) { Log::info('API Response', [ 'status' => $response->status(), 'url' => $response->effectiveUri(), ]); return $response; });
|
测试 HTTP 客户端
伪造响应
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| use Illuminate\Support\Facades\Http;
Http::fake();
Http::fake([ 'github.com/*' => Http::response(['foo' => 'bar'], 200), 'google.com/*' => Http::response('Hello World', 200), ]);
Http::fake([ 'example.com/*' => Http::response(['error' => 'Not found'], 404), ]);
Http::fake([ 'example.com/*' => Http::sequence() ->push(['page' => 1], 200) ->push(['page' => 2], 200) ->pushStatus(404), ]);
|
断言请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| Http::fake();
Http::withHeaders(['Authorization' => 'Bearer token']) ->post('https://api.example.com/users', ['name' => 'John']);
Http::assertSent(function ($request) { return $request->url() === 'https://api.example.com/users' && $request->hasHeader('Authorization', 'Bearer token') && $request['name'] === 'John'; });
Http::assertNotSent(function ($request) { return $request->url() === 'https://api.example.com/other'; });
Http::assertNothingSent(); Http::assertSentCount(2);
|
最佳实践
1. 使用宏封装 API
1 2 3 4 5 6
| Http::macro('stripe', function () { return Http::withBasicAuth(config('stripe.secret'), '') ->baseUrl('https://api.stripe.com/v1'); });
$response = Http::stripe()->post('/charges', $data);
|
2. 处理错误
1 2 3 4 5 6 7 8 9 10 11
| $response = Http::retry(3, 100)->get('https://api.example.com/users');
if ($response->failed()) { Log::error('API request failed', [ 'status' => $response->status(), 'body' => $response->body(), ]); return null; }
return $response->json();
|
3. 使用并发请求
1 2 3 4 5 6 7 8 9
| $responses = Http::pool(fn (Pool $pool) => [ $pool->as('users')->get('/users'), $pool->as('posts')->get('/posts'), ]);
$users = Http::get('/users'); $posts = Http::get('/posts');
|
总结
Laravel 13 的 HTTP 客户端提供了强大而优雅的 HTTP 请求能力。通过合理使用请求头、超时重试、并发请求和错误处理,可以构建出可靠的 API 集成。记住使用宏封装常用 API、使用并发请求提高性能、并充分利用测试功能来验证 HTTP 请求。HTTP 客户端是与外部服务交互的重要工具,掌握它对于构建现代 Web 应用至关重要。