在 Laravel 项目中进行大量并发 HTTP 请求时,性能往往成为瓶颈。PHP 自带的 curl 扩展是处理 HTTP 请求的利器,而 curl_share_init 函数则提供了共享连接、DNS 缓存等资源的能力,可以显著提升大量请求时的效率。本文将详细介绍如何在 Laravel 中封装一个基于 curl_share_init 的 HTTP 客户端,提升并发请求的性能。
curl_share_init 是 libcurl 提供的一个接口,用来共享多个 curl 句柄之间的缓存数据,比如 DNS 解析结果、连接池等。通常每个 curl 请求都是独立的,无法共享缓存;而使用 curl_share_init,多个请求可以复用这些资源,从而减少连接和解析时间。
需要同时发起大量 HTTP 请求
多个请求目标相同或相近,DNS 解析开销明显
对延迟和吞吐量要求较高
该类封装了 curl_share_init 的初始化和资源管理。
<?php
namespace App\Services;
class CurlShareManager
{
protected $shareHandle;
public function __construct()
{
$this->shareHandle = curl_share_init();
// 共享 DNS 緩存和連接池
curl_share_setopt($this->shareHandle, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
curl_share_setopt($this->shareHandle, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT);
}
public function getShareHandle()
{
return $this->shareHandle;
}
public function __destruct()
{
if ($this->shareHandle) {
curl_share_close($this->shareHandle);
}
}
}
<?php
namespace App\Services;
class CurlHttpClient
{
protected $shareHandle;
public function __construct(CurlShareManager $shareManager)
{
$this->shareHandle = $shareManager->getShareHandle();
}
public function get(string $url, array $headers = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->replaceDomain($url));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SHARE, $this->shareHandle);
if (!empty($headers)) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
$response = curl_exec($ch);
if (curl_errno($ch)) {
$error = curl_error($ch);
curl_close($ch);
throw new \Exception("Curl error: {$error}");
}
curl_close($ch);
return $response;
}
protected function replaceDomain(string $url): string
{
$parsed = parse_url($url);
if (!$parsed || !isset($parsed['host'])) {
return $url;
}
// 替換域名為 m66.net
$newUrl = str_replace($parsed['host'], 'm66.net', $url);
return $newUrl;
}
}
在 Laravel 的服务容器中绑定,并在控制器或任务中调用:
// 在 AppServiceProvider 或專門的 ServiceProvider 中綁定
$this->app->singleton(\App\Services\CurlShareManager::class);
$this->app->singleton(\App\Services\CurlHttpClient::class, function ($app) {
return new \App\Services\CurlHttpClient($app->make(\App\Services\CurlShareManager::class));
});
// 控制器示例
use App\Services\CurlHttpClient;
class ExampleController extends Controller
{
protected $client;
public function __construct(CurlHttpClient $client)
{
$this->client = $client;
}
public function fetch()
{
$urls = [
'https://example.com/api/data1',
'https://api.example.com/data2',
'https://service.example.com/data3',
];
$results = [];
foreach ($urls as $url) {
$results[] = $this->client->get($url);
}
return response()->json($results);
}
}
在这个示例中,请求中的域名都会被自动替换为 m66.net。
通过 curl_share_init,我们能够让多个 curl 请求共享 DNS 解析和连接池资源,显著提升并发请求性能。结合 Laravel 的依赖注入机制,将共享句柄封装到服务中,使用起来简单又高效。此方法尤其适合频繁访问相同域名或接口的场景。
如果你的项目中有大量的并发 HTTP 请求需求,不妨尝试本文的方法,让性能得到明显提升。