在 Laravel 项目中,支付、短信、物流、天气和数据同步等功能都可能需要调用第三方 API。Laravel 提供的 HTTP Client 基于 Guzzle 封装,支持请求参数、请求头、超时、状态判断、重试和异常处理,可以减少直接操作底层 HTTP 客户端的代码。
一、发起 GET 请求
Laravel 的 HTTP Client 通过 Http Facade 发起请求:
use Illuminate\Support\Facades\Http;
$response = Http::get('https://api.example.com/users');
可以使用 json() 获取 JSON 响应:
$data = $response->json();
完整示例:
use Illuminate\Support\Facades\Http;
$response = Http::get('https://api.example.com/users');
if ($response->successful()) {
$users = $response->json();
} else {
$users = [];
}
successful() 用于判断响应状态码是否为 2xx。
二、传递查询参数
使用 withQueryParameters() 添加 URL 查询参数:
$response = Http::withQueryParameters([
'page' => 1,
'limit' => 20,
])->get('https://api.example.com/users');
实际请求地址类似:
https://api.example.com/users?page=1&limit=20
如果项目使用的 Laravel 版本不支持 withQueryParameters(),也可以直接将参数作为 get() 的第二个参数:
$response = Http::get('https://api.example.com/users', [
'page' => 1,
'limit' => 20,
]);
三、发送 POST 请求
使用 post() 方法发送 JSON 请求:
use Illuminate\Support\Facades\Http;
$response = Http::post('https://api.example.com/orders', [
'user_id' => 1001,
'amount' => 19900,
]);
Laravel 会将数组作为 JSON 请求体发送。也可以使用 asForm() 发送表单格式数据:
$response = Http::asForm()->post('https://api.example.com/login', [
'username' => 'demo',
'password' => 'example-password',
]);
密码等敏感信息不应直接写入代码,应从环境变量或安全配置中读取。
四、设置请求头
通过 withHeaders() 设置请求头:
$response = Http::withHeaders([
'Accept' => 'application/json',
'X-Client-Version' => '1.0.0',
])->get('https://api.example.com/profile');
调用需要 Bearer Token 的接口时,可以使用:
$response = Http::withToken($token)
->acceptJson()
->get('https://api.example.com/profile');
$token 应来自安全配置或数据库中的有效凭证,不能提交到公开代码仓库。
五、设置超时时间
第三方接口响应过慢时,可能拖延当前请求。可以设置连接超时和整体请求超时:
$response = Http::connectTimeout(3)
->timeout(10)
->get('https://api.example.com/status');
其中:
connectTimeout(3):连接服务器最多等待 3 秒。timeout(10):整个请求最多等待 10 秒。
实际时间应结合业务场景设置。支付、订单和数据同步等接口需要根据服务商要求设计超时策略。
六、判断请求结果
Laravel HTTP Client 提供多种状态判断方法:
if ($response->successful()) {
// 2xx
}
if ($response->failed()) {
// 4xx 或 5xx
}
if ($response->clientError()) {
// 4xx
}
if ($response->serverError()) {
// 5xx
}
也可以直接判断状态码:
if ($response->status() === 200) {
$data = $response->json();
}
如果只接受成功响应,可以使用 throw():
$response = Http::get('https://api.example.com/users')
->throw();
$data = $response->json();
当接口返回 4xx 或 5xx 时,throw() 会抛出异常。业务代码可以通过 try...catch 进行处理:
use Illuminate\Http\Client\RequestException;
use Illuminate\Support\Facades\Http;
try {
$response = Http::timeout(10)
->get('https://api.example.com/users')
->throw();
$data = $response->json();
} catch (RequestException $exception) {
report($exception);
$data = [];
}
七、处理请求失败和重试
网络抖动、服务临时过载或网关错误可能导致请求失败。可以使用 retry() 自动重试:
$response = Http::retry(3, 200)
->timeout(10)
->get('https://api.example.com/status');
这表示最多尝试 3 次,每次重试间隔 200 毫秒。
如果希望只对特定异常进行重试,可以传入闭包:
$response = Http::retry(3, 200, function (
\Exception $exception,
$request
) {
return $exception instanceof \Illuminate\Http\Client\ConnectionException;
})->get('https://api.example.com/status');
对于支付、订单创建等可能产生业务副作用的请求,不能简单重复发送。重试前应确认接口是否支持幂等键,否则可能造成重复订单或重复扣款。
八、封装第三方 API 服务
当多个控制器都需要调用同一个接口时,可以将请求逻辑放到服务类中。
创建文件:
app/Services/WeatherService.php
写入:
<?php
namespace App\Services;
use Illuminate\Support\Facades\Http;
class WeatherService
{
public function getCityWeather(string $city): array
{
$response = Http::acceptJson()
->connectTimeout(3)
->timeout(10)
->retry(2, 200)
->get(config('services.weather.url'), [
'city' => $city,
])
->throw();
return $response->json();
}
}
在 config/services.php 中配置地址:
'weather' => [
'url' => env('WEATHER_API_URL'),
],
在 .env 中设置:
WEATHER_API_URL=https://api.example.com/weather
控制器中调用:
use App\Services\WeatherService;
class WeatherController
{
public function show(
WeatherService $weatherService,
string $city
) {
return response()->json(
$weatherService->getCityWeather($city)
);
}
}
将地址放入配置文件后,可以根据开发、测试和生产环境使用不同的接口地址。
九、测试 HTTP 请求
Laravel 支持使用 Http::fake() 模拟外部接口:
use Illuminate\Support\Facades\Http;
Http::fake([
'api.example.com/*' => Http::response([
'status' => 'ok',
], 200),
]);
然后执行业务代码:
$response = Http::get('https://api.example.com/status');
$this->assertTrue($response->successful());
还可以验证请求是否发送了正确参数:
Http::assertSent(function ($request) {
return $request->url() === 'https://api.example.com/status'
&& $request->header('Accept')[0] === 'application/json';
});
测试时使用模拟响应,可以避免频繁调用真实第三方接口。
十、常见问题
HTTP Client 请求失败会自动重试吗?
不会。只有调用 retry() 后,Laravel 才会按照指定次数和间隔进行重试。
timeout() 和 connectTimeout() 有什么区别?
connectTimeout() 控制建立连接的等待时间,timeout() 控制整个请求的最大执行时间。实际接口调用通常建议同时设置。
所有接口都适合自动重试吗?
不适合。查询类请求通常更容易重试,创建订单、支付和扣库存等操作需要先确认接口幂等机制。

