PHP cURL 并发请求怎么发

wen PHP项目 1

本文目录导读:

PHP cURL 并发请求怎么发

  1. *curlmulti 函数(最常用)**
  2. 封装成可复用函数
  3. 使用生成器模式(PHP 5.5+)
  4. 使用 Guzzle 库(推荐)
  5. 处理动态添加请求
  6. 注意事项

在 PHP 中实现 cURL 并发请求主要有以下几种方法,我来详细介绍:

*curlmulti 函数(最常用)**

这是 PHP 官方提供的并发处理方案:

<?php
// 准备多个请求
$urls = [
    'https://api.example.com/users',
    'https://api.example.com/posts',
    'https://api.example.com/comments'
];
// 创建 cURL 多重句柄
$mh = curl_multi_init();
$handles = [];
// 为每个 URL 创建单独的 cURL 句柄
foreach ($urls as $key => $url) {
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
    // 添加到多重句柄
    curl_multi_add_handle($mh, $ch);
    $handles[$key] = $ch;
}
// 执行并发请求
$running = null;
do {
    curl_multi_exec($mh, $running);
    curl_multi_select($mh); // 等待活动连接
} while ($running > 0);
// 获取结果
$results = [];
foreach ($handles as $key => $ch) {
    $results[$key] = curl_multi_getcontent($ch);
    curl_multi_remove_handle($mh, $ch);
    curl_close($ch);
}
// 关闭多重句柄
curl_multi_close($mh);
// 输出结果
print_r($results);
?>

封装成可复用函数

<?php
/**
 * 并发请求函数
 * @param array $requests 请求配置数组
 * @return array 响应结果
 */
function multiCurlRequest(array $requests) {
    $mh = curl_multi_init();
    $handles = [];
    foreach ($requests as $key => $request) {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $request['url']);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        // 设置请求方法
        $method = isset($request['method']) ? strtoupper($request['method']) : 'GET';
        if ($method === 'POST') {
            curl_setopt($ch, CURLOPT_POST, true);
            if (isset($request['post_data'])) {
                curl_setopt($ch, CURLOPT_POSTFIELDS, $request['post_data']);
            }
        }
        // 设置请求头
        if (isset($request['headers'])) {
            curl_setopt($ch, CURLOPT_HTTPHEADER, $request['headers']);
        }
        // 设置超时
        $timeout = isset($request['timeout']) ? $request['timeout'] : 30;
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
        // 是否SSL验证
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_multi_add_handle($mh, $ch);
        $handles[$key] = $ch;
    }
    // 执行并发请求
    $running = null;
    do {
        $status = curl_multi_exec($mh, $running);
        if ($running) {
            curl_multi_select($mh);
        }
    } while ($running > 0 && $status === CURLM_OK);
    // 收集结果
    $results = [];
    foreach ($handles as $key => $ch) {
        $results[$key] = [
            'content' => curl_multi_getcontent($ch),
            'error' => curl_error($ch),
            'errno' => curl_errno($ch),
            'info' => curl_getinfo($ch)
        ];
        curl_multi_remove_handle($mh, $ch);
        curl_close($ch);
    }
    curl_multi_close($mh);
    return $results;
}
// 使用示例
$requests = [
    'user' => [
        'url' => 'https://api.example.com/user/1',
        'method' => 'GET',
        'timeout' => 10
    ],
    'post' => [
        'url' => 'https://api.example.com/post/create',
        'method' => 'POST',
        'post_data' => ['title' => 'Hello', 'content' => 'World'],
        'timeout' => 15
    ],
    'search' => [
        'url' => 'https://api.example.com/search?q=php',
        'method' => 'GET',
        'headers' => ['Authorization: Bearer token']
    ]
];
$results = multiCurlRequest($requests);
foreach ($results as $key => $result) {
    echo "请求 {$key} 结果:\n";
    echo "状态码: " . $result['info']['http_code'] . "\n";
    echo "内容: " . $result['content'] . "\n\n";
}
?>

使用生成器模式(PHP 5.5+)

<?php
// 使用 Generator 处理流式响应
class MultiCurlHandler {
    private $mh;
    private $channels = [];
    public function __construct() {
        $this->mh = curl_multi_init();
    }
    public function addRequest($name, $url, $options = []) {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        foreach ($options as $opt => $value) {
            curl_setopt($ch, $opt, $value);
        }
        curl_multi_add_handle($this->mh, $ch);
        $this->channels[$name] = $ch;
        return $this;
    }
    public function execute() {
        $running = null;
        do {
            curl_multi_exec($this->mh, $running);
            curl_multi_select($this->mh);
        } while ($running > 0);
        $results = [];
        foreach ($this->channels as $name => $ch) {
            $results[$name] = curl_multi_getcontent($ch);
            curl_multi_remove_handle($this->mh, $ch);
            curl_close($ch);
        }
        curl_multi_close($this->mh);
        return $results;
    }
}
// 使用
$handler = new MultiCurlHandler();
$handler->addRequest('google', 'https://www.google.com')
        ->addRequest('baidu', 'https://www.baidu.com')
        ->addRequest('github', 'https://api.github.com');
$results = $handler->execute();
print_r($results);
?>

使用 Guzzle 库(推荐)

如果允许使用第三方库,Guzzle 提供了更优雅的方式:

<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Promise;
$client = new Client(['timeout' => 10]);
// 创建多个请求
$promises = [
    'users' => $client->getAsync('https://api.example.com/users'),
    'posts' => $client->getAsync('https://api.example.com/posts'),
    'comments' => $client->getAsync('https://api.example.com/comments'),
];
// 等待所有请求完成
$results = Promise\Utils::settle($promises)->wait();
// 处理结果
foreach ($results as $key => $result) {
    if ($result['state'] === 'fulfilled') {
        echo "{$key}: " . $result['value']->getBody() . "\n";
    } else {
        echo "{$key} 失败: " . $result['reason'] . "\n";
    }
}
?>

处理动态添加请求

<?php
// 分批处理大量请求
function processManyRequests(array $urls, $batchSize = 10) {
    $allResults = [];
    foreach (array_chunk($urls, $batchSize) as $batch) {
        $mh = curl_multi_init();
        $handles = [];
        foreach ($batch as $key => $url) {
            $ch = curl_init($url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_multi_add_handle($mh, $ch);
            $handles[$key] = $ch;
        }
        $running = null;
        do {
            curl_multi_exec($mh, $running);
            curl_multi_select($mh);
        } while ($running > 0);
        foreach ($handles as $key => $ch) {
            $allResults[$key] = curl_multi_getcontent($ch);
            curl_multi_remove_handle($mh, $ch);
            curl_close($ch);
        }
        curl_multi_close($mh);
    }
    return $allResults;
}
?>

注意事项

  1. 超时设置:一定要设置超时,避免请求无限等待
  2. 错误处理:检查 curl_error() 确保请求成功
  3. 资源清理:使用完要关闭所有句柄
  4. 限制并发数:避免一次性发起过多请求
  5. SSL 验证:生产环境建议启用 SSL 验证

选择哪种方式取决于你的需求和项目环境,如果是新项目,推荐使用 Guzzle;如果不想引入依赖,使用 curlmulti* 就足够了。

抱歉,评论功能暂时关闭!