Skip to content

cURL 详解

cURL(Client URL Library)是 PHP 中最强大、最常用的网络请求扩展。它基于 libcurl 库,支持 HTTP、HTTPS、FTP、SCP、LDAP 等多种协议,是现代 PHP 应用与外部服务通信的核心工具。本节将全面讲解 cURL 的基础用法、配置选项和常见场景。

前置知识

阅读本节前,建议先了解:PHP 基础语法函数与闭包

基础概念

什么是 cURL

cURL 是一个利用 URL 语法传输数据的命令行工具和库。PHP 的 cURL 扩展(ext-curl)是对 libcurl 的封装,提供了面向过程和面向对象两种编程接口。

cURL 能做什么

  • 发送 HTTP/HTTPS 请求(GET、POST、PUT、DELETE、PATCH 等)
  • 上传和下载文件
  • 处理 Cookie 和 Session
  • SSL/TLS 证书验证
  • 代理服务器配置
  • HTTP 认证(Basic、Digest、Bearer 等)
  • 请求超时控制
  • 自定义 HTTP 头
  • 响应头解析

安装与启用

大多数 PHP 发行版默认包含 cURL 扩展。确认扩展是否已启用:

php
<?php
declare(strict_types=1);

// 检查 cURL 扩展是否已加载
if (!extension_loaded('curl')) {
    echo "cURL 扩展未启用" . PHP_EOL;
} else {
    echo "cURL 版本: " . curl_version()['version'] . PHP_EOL;
    echo "libcurl 版本: " . curl_version()['version_number'] . PHP_EOL;
}

在 Linux 上安装:

bash
# Ubuntu/Debian
sudo apt-get install php-curl

# CentOS/RHEL
sudo yum install php-curl

# 编译安装时
./configure --with-curl

基本语法

cURL 请求生命周期

一个完整的 cURL 请求包含以下步骤:

  1. 初始化curl_init() 创建 cURL 句柄
  2. 配置选项curl_setopt() / curl_setopt_array() 设置请求参数
  3. 执行请求curl_exec() 发送请求并获取响应
  4. 获取信息curl_getinfo() 获取请求信息
  5. 处理错误curl_errno() / curl_error() 错误处理
  6. 关闭句柄curl_close() 释放资源

发送 GET 请求

php
<?php
declare(strict_types=1);

function httpGet(string $url, array $headers = []): string
{
    // 1. 初始化 cURL 句柄
    $ch = curl_init();

    // 2. 设置请求选项
    curl_setopt_array($ch, [
        CURLOPT_URL            => $url,
        CURLOPT_RETURNTRANSFER => true,  // 将响应作为字符串返回
        CURLOPT_HEADER         => false, // 不包含响应头
        CURLOPT_FOLLOWLOCATION => true,  // 跟随重定向
        CURLOPT_MAXREDIRS      => 10,    // 最大重定向次数
        CURLOPT_ENCODING       => '',    // 自动处理压缩编码(gzip、deflate)
        CURLOPT_CONNECTTIMEOUT => 30,    // 连接超时(秒)
        CURLOPT_TIMEOUT        => 60,    // 总超时(秒)
        CURLOPT_HTTPHEADER     => $headers,
    ]);

    // 3. 执行请求
    $response = curl_exec($ch);

    // 4. 错误检查
    if ($response === false) {
        $errno  = curl_errno($ch);
        $error  = curl_error($ch);
        curl_close($ch);
        throw new RuntimeException("cURL 请求失败 [{$errno}]: {$error}");
    }

    // 5. 获取请求信息
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $totalTime = curl_getinfo($ch, CURLINFO_TOTAL_TIME);

    // 6. 关闭句柄
    curl_close($ch);

    if ($httpCode >= 400) {
        throw new RuntimeException("HTTP 请求失败,状态码: {$httpCode}");
    }

    return $response;
}

// 使用示例
try {
    $data = httpGet('https://api.example.com/users');
    echo $data;
} catch (RuntimeException $e) {
    echo "错误: " . $e->getMessage() . PHP_EOL;
}

发送 POST 请求

php
<?php
declare(strict_types=1);

function httpPost(
    string $url,
    array|string $data = [],
    array $headers = [],
    string $contentType = 'json'
): string {
    $ch = curl_init();

    // 根据内容类型处理请求体
    if ($contentType === 'json') {
        $payload = is_array($data) ? json_encode($data) : $data;
        $headers[] = 'Content-Type: application/json';
    } elseif ($contentType === 'form') {
        $payload = is_array($data) ? http_build_query($data) : $data;
        $headers[] = 'Content-Type: application/x-www-form-urlencoded';
    } else {
        $payload = is_array($data) ? json_encode($data) : $data;
    }

    curl_setopt_array($ch, [
        CURLOPT_URL            => $url,
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => $payload,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HEADER         => false,
        CURLOPT_HTTPHEADER     => $headers,
        CURLOPT_TIMEOUT        => 30,
    ]);

    $response = curl_exec($ch);

    if ($response === false) {
        $error = curl_error($ch);
        curl_close($ch);
        throw new RuntimeException("POST 请求失败: {$error}");
    }

    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    return $response;
}

// JSON POST 示例
$response = httpPost('https://api.example.com/users', [
    'name'  => '张三',
    'email' => 'zhangsan@example.com',
]);
echo $response;

// 表单 POST 示例
$response = httpPost(
    'https://api.example.com/login',
    [
        'username' => 'admin',
        'password' => 'secret',
    ],
    [],
    'form'
);

详细说明

CURLOPT 常用选项一览

基础选项

选项类型默认值说明
CURLOPT_URLstring-请求的 URL
CURLOPT_RETURNTRANSFERboolfalse为 true 时返回响应字符串而非直接输出
CURLOPT_HEADERboolfalse为 true 时在响应中包含头部
CURLOPT_FOLLOWLOCATIONboolfalse跟随 HTTP 重定向
CURLOPT_MAXREDIRSint-最大重定向次数(需配合 FOLLOWLOCATION)
CURLOPT_CUSTOMREQUESTstring-自定义 HTTP 方法(PUT、DELETE、PATCH)

超时选项

选项类型默认值说明
CURLOPT_TIMEOUTint0(无限)请求最大执行时间(秒)
CURLOPT_CONNECTTIMEOUTint300尝试连接的最长时间(秒)
CURLOPT_TIMEOUT_MSint-以毫秒为单位的超时(7.16.2+)

SSL/TLS 选项

php
<?php
declare(strict_types=1);

function secureRequest(string $url): string
{
    $ch = curl_init();

    curl_setopt_array($ch, [
        CURLOPT_URL                => $url,
        CURLOPT_RETURNTRANSFER     => true,
        CURLOPT_SSL_VERIFYPEER    => true,   // 验证对等证书(生产环境必须为 true)
        CURLOPT_SSL_VERIFYHOST    => 2,      // 检查主机名与证书匹配
        CURLOPT_CERTINFO          => true,    // 获取证书信息
        CURLOPT_CAINFO            => '/path/to/cacert.pem', // CA 证书路径
        // 也可以通过环境变量指定
        // CURLOPT_CAPATH          => '/path/to/certs/',  // CA 证书目录
    ]);

    $response = curl_exec($ch);

    if ($response === false) {
        $error = curl_error($ch);
        curl_close($ch);
        throw new RuntimeException("安全请求失败: {$error}");
    }

    // 获取 SSL 证书详情
    $certInfo = curl_getinfo($ch, CURLINFO_CERTINFO);
    curl_close($ch);

    return $response;
}

安全警告

在生产环境中,永远不要CURLOPT_SSL_VERIFYPEER 设置为 false。禁用 SSL 验证会使应用面临中间人攻击(MITM)的风险。如果遇到证书验证问题,应正确配置 CA 证书路径。

HTTP 方法

php
<?php
declare(strict_types=1);

class HttpClient
{
    private string $baseUrl;
    private array $defaultHeaders;
    private int $timeout;

    public function __construct(
        string $baseUrl,
        array $defaultHeaders = [],
        int $timeout = 30
    ) {
        $this->baseUrl = rtrim($baseUrl, '/');
        $this->defaultHeaders = array_merge([
            'Accept: application/json',
            'Content-Type: application/json',
        ], $defaultHeaders);
        $this->timeout = $timeout;
    }

    public function request(
        string $method,
        string $path,
        array|string|null $data = null
    ): array {
        $url = $this->baseUrl . '/' . ltrim($path, '/');

        $ch = curl_init();

        $options = [
            CURLOPT_URL            => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT        => $this->timeout,
            CURLOPT_CUSTOMREQUEST  => strtoupper($method),
            CURLOPT_HTTPHEADER     => $this->defaultHeaders,
        ];

        if ($data !== null) {
            $options[CURLOPT_POSTFIELDS] = json_encode($data);
        }

        curl_setopt_array($ch, $options);

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $info = curl_getinfo($ch);

        if ($response === false) {
            $error = curl_error($ch);
            curl_close($ch);
            throw new RuntimeException("请求失败: {$error}");
        }

        curl_close($ch);

        return [
            'status_code' => $httpCode,
            'body'        => $response,
            'info'        => $info,
        ];
    }

    public function get(string $path): array
    {
        return $this->request('GET', $path);
    }

    public function post(string $path, array $data): array
    {
        return $this->request('POST', $path, $data);
    }

    public function put(string $path, array $data): array
    {
        return $this->request('PUT', $path, $data);
    }

    public function delete(string $path): array
    {
        return $this->request('DELETE', $path);
    }

    public function patch(string $path, array $data): array
    {
        return $this->request('PATCH', $path, $data);
    }
}

// 使用示例
$client = new HttpClient('https://api.example.com/v1');

// GET
$users = $client->get('users');

// POST
$newUser = $client->post('users', [
    'name'  => '李四',
    'email' => 'lisi@example.com',
]);

// PUT
$updated = $client->put('users/1', [
    'name' => '李四(已更新)',
]);

// DELETE
$client->delete('users/1');

// PATCH
$patched = $client->patch('users/2', [
    'email' => 'newemail@example.com',
]);
php
<?php
declare(strict_types=1);

function requestWithCookies(string $url): string
{
    $cookieFile = sys_get_temp_dir() . '/curl_cookies.txt';

    $ch = curl_init();

    curl_setopt_array($ch, [
        CURLOPT_URL            => $url,
        CURLOPT_RETURNTRANSFER => true,

        // Cookie 选项
        CURLOPT_COOKIEJAR     => $cookieFile,  // 保存 Cookie 到文件
        CURLOPT_COOKIEFILE    => $cookieFile,  // 从文件读取 Cookie

        // 或者直接设置 Cookie 字符串
        // CURLOPT_COOKIE       => 'session_id=abc123; user=john',

        // Cookie 相关行为
        CURLOPT_COOKIESESSION => true,  // 忽略先前保存的 Cookie(仅发起新的会话)
    ]);

    $response = curl_exec($ch);
    curl_close($ch);

    return $response;
}

响应头获取

php
<?php
declare(strict_types=1);

function fetchWithHeaders(string $url): array
{
    $responseHeaders = [];
    $ch = curl_init();

    // 使用回调函数捕获响应头
    curl_setopt_array($ch, [
        CURLOPT_URL            => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HEADERFUNCTION => function (
            $ch,
            string $header
        ) use (&$responseHeaders): int {
            $len = strlen($header);

            // 跳过状态行和空行
            if ($len > 2) {
                $parts = explode(':', $header, 2);
                if (count($parts) === 2) {
                    $key = trim($parts[0]);
                    $value = trim($parts[1]);
                    $responseHeaders[$key] = $value;
                }
            }

            return $len;
        },
    ]);

    $body = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

    if ($body === false) {
        $error = curl_error($ch);
        curl_close($ch);
        throw new RuntimeException("请求失败: {$error}");
    }

    curl_close($ch);

    return [
        'status_code' => $httpCode,
        'headers'     => $responseHeaders,
        'body'        => $body,
    ];
}

// 使用示例
$result = fetchWithHeaders('https://api.example.com/data');
echo "状态码: {$result['status_code']}" . PHP_EOL;
echo "Content-Type: {$result['headers']['Content-Type']}" . PHP_EOL;
echo "响应体: {$result['body']}" . PHP_EOL;

认证方式

php
<?php
declare(strict_types=1);

// Basic 认证
function requestWithBasicAuth(
    string $url,
    string $username,
    string $password
): string {
    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL            => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPAUTH      => CURLAUTH_BASIC,
        CURLOPT_USERPWD       => "{$username}:{$password}",
    ]);

    $response = curl_exec($ch);
    curl_close($ch);
    return $response !== false ? $response : throw new RuntimeException(curl_error($ch));
}

// Bearer Token 认证
function requestWithBearerToken(string $url, string $token): string
{
    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL            => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER     => [
            'Authorization: Bearer ' . $token,
            'Accept: application/json',
        ],
    ]);

    $response = curl_exec($ch);
    curl_close($ch);
    return $response !== false ? $response : throw new RuntimeException(curl_error($ch));
}

// Digest 认证
function requestWithDigestAuth(
    string $url,
    string $username,
    string $password
): string {
    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL            => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPAUTH      => CURLAUTH_DIGEST,
        CURLOPT_USERPWD       => "{$username}:{$password}",
    ]);

    $response = curl_exec($ch);
    curl_close($ch);
    return $response !== false ? $response : throw new RuntimeException(curl_error($ch));
}

代理配置

php
<?php
declare(strict_types=1);

function requestViaProxy(
    string $url,
    string $proxyHost,
    int $proxyPort,
    ?string $proxyAuth = null
): string {
    $ch = curl_init();

    $options = [
        CURLOPT_URL            => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_PROXY          => "{$proxyHost}:{$proxyPort}",
        CURLOPT_PROXYTYPE      => CURLPROXY_HTTP, // HTTP 代理
        // CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A, CURLPROXY_SOCKS5 也可用
    ];

    if ($proxyAuth !== null) {
        $options[CURLOPT_PROXYUSERPWD] = $proxyAuth;
    }

    curl_setopt_array($ch, $options);

    $response = curl_exec($ch);

    if ($response === false) {
        $error = curl_error($ch);
        curl_close($ch);
        throw new RuntimeException("代理请求失败: {$error}");
    }

    curl_close($ch);
    return $response;
}

// SOCKS5 代理示例
function requestViaSocks5(
    string $url,
    string $proxyHost,
    int $proxyPort
): string {
    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL            => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_PROXY          => "{$proxyHost}:{$proxyPort}",
        CURLOPT_PROXYTYPE      => CURLPROXY_SOCKS5,
    ]);

    $response = curl_exec($ch);
    curl_close($ch);
    return $response !== false ? $response : throw new RuntimeException(curl_error($ch));
}

curl_getinfo 获取信息

curl_getinfo() 返回请求执行后的详细信息:

php
<?php
declare(strict_types=1);

function getInfo(string $url): array
{
    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL            => $url,
        CURLOPT_RETURNTRANSFER => true,
    ]);

    curl_exec($ch);

    // 获取全部信息
    $allInfo = curl_getinfo($ch);

    // 获取单个信息
    $httpCode   = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $totalTime  = curl_getinfo($ch, CURLINFO_TOTAL_TIME);
    $namelookup = curl_getinfo($ch, CURLINFO_NAMELOOKUP_TIME);
    $connect    = curl_getinfo($ch, CURLINFO_CONNECT_TIME);
    $pretransfer = curl_getinfo($ch, CURLINFO_PRETRANSFER_TIME);
    $startTransfer = curl_getinfo($ch, CURLINFO_STARTTRANSFER_TIME);
    $redirectCount = curl_getinfo($ch, CURLINFO_REDIRECT_COUNT);
    $sizeUpload    = curl_getinfo($ch, CURLINFO_SIZE_UPLOAD);
    $sizeDownload  = curl_getinfo($ch, CURLINFO_SIZE_DOWNLOAD);
    $speedDownload = curl_getinfo($ch, CURLINFO_SPEED_DOWNLOAD);
    $url           = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
    $contentType   = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);

    curl_close($ch);

    return [
        'http_code'      => $httpCode,
        'total_time'     => $totalTime,
        'dns_time'       => $namelookup,
        'connect_time'   => $connect,
        'transfer_time'  => $startTransfer,
        'download_speed' => $speedDownload,
        'download_size'  => $sizeDownload,
        'upload_size'    => $sizeUpload,
        'effective_url'  => $url,
        'content_type'   => $contentType,
    ];
}

实战示例

REST API 客户端

php
<?php
declare(strict_types=1);

/**
 * 通用 REST API 客户端
 */
class ApiClient
{
    private string $baseUrl;
    private string $token;
    private array $headers = [];
    private int $timeout;
    private int $connectTimeout;

    public function __construct(
        string $baseUrl,
        string $token = '',
        int $timeout = 30,
        int $connectTimeout = 10
    ) {
        $this->baseUrl = rtrim($baseUrl, '/');
        $this->token = $token;
        $this->timeout = $timeout;
        $this->connectTimeout = $connectTimeout;
    }

    public function setHeaders(array $headers): self
    {
        $this->headers = $headers;
        return $this;
    }

    public function setTimeout(int $timeout): self
    {
        $this->timeout = $timeout;
        return $this;
    }

    public function request(
        string $method,
        string $uri,
        array $data = [],
        array $query = []
    ): array {
        $url = $this->buildUrl($uri, $query);
        $ch = $this->createHandle($method, $url, $data);

        $response = $this->execute($ch);
        curl_close($ch);

        return $response;
    }

    private function buildUrl(string $uri, array $query): string
    {
        $url = $this->baseUrl . '/' . ltrim($uri, '/');
        if (!empty($query)) {
            $url .= '?' . http_build_query($query);
        }
        return $url;
    }

    private function createHandle(
        string $method,
        string $url,
        array $data
    ): \CurlHandle {
        $ch = curl_init();

        $headers = array_merge(
            [
                'Accept: application/json',
                'Content-Type: application/json',
                'User-Agent: PHP-ApiClient/1.0',
            ],
            $this->headers
        );

        if (!empty($this->token)) {
            $headers[] = "Authorization: Bearer {$this->token}";
        }

        $options = [
            CURLOPT_URL            => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT        => $this->timeout,
            CURLOPT_CONNECTTIMEOUT => $this->connectTimeout,
            CURLOPT_CUSTOMREQUEST  => strtoupper($method),
            CURLOPT_HTTPHEADER     => $headers,
            CURLOPT_ENCODING       => '',
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_MAXREDIRS      => 5,
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_SSL_VERIFYHOST => 2,
        ];

        if (!empty($data) && in_array(strtoupper($method), ['POST', 'PUT', 'PATCH'])) {
            $options[CURLOPT_POSTFIELDS] = json_encode($data);
        }

        curl_setopt_array($ch, $options);

        return $ch;
    }

    private function execute(\CurlHandle $ch): array
    {
        $body = curl_exec($ch);

        if ($body === false) {
            throw new RuntimeException(
                "cURL 错误 [" . curl_errno($ch) . "]: " . curl_error($ch)
            );
        }

        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $info = curl_getinfo($ch);

        $decoded = json_decode($body, true);

        return [
            'status' => $httpCode,
            'data'   => $decoded,
            'raw'    => $body,
            'info'   => $info,
        ];
    }
}

// 使用示例
$client = new ApiClient('https://jsonplaceholder.typicode.com');

// 获取用户列表
$users = $client->get('users');

// 获取单个用户
$user = $client->get('users/1');

// 创建文章
$post = $client->post('posts', [
    'title'  => 'Hello World',
    'body'   => 'This is a test post.',
    'userId' => 1,
]);

// 更新文章
$updated = $client->put('posts/1', [
    'title' => 'Updated Title',
]);

// 删除文章
$client->delete('posts/1');

// 带查询参数的请求
$filtered = $client->get('posts', query: ['userId' => 1]);

请求重试机制

php
<?php
declare(strict_types=1);

class RetryableCurlClient
{
    private int $maxRetries;
    private int $retryDelay;
    private array $retryableStatusCodes = [
        429,  // Too Many Requests
        500,  // Internal Server Error
        502,  // Bad Gateway
        503,  // Service Unavailable
        504,  // Gateway Timeout
    ];

    public function __construct(int $maxRetries = 3, int $retryDelay = 1000)
    {
        $this->maxRetries = $maxRetries;
        $this->retryDelay = $retryDelay;
    }

    public function get(string $url): string
    {
        $lastException = null;
        $attempt = 0;

        while ($attempt < $this->maxRetries) {
            $attempt++;

            try {
                $response = $this->doRequest($url);
                return $response;
            } catch (RuntimeException $e) {
                $lastException = $e;

                if ($attempt < $this->maxRetries) {
                    // 指数退避
                    $delay = $this->retryDelay * (2 ** ($attempt - 1));
                    usleep($delay * 1000); // 微秒转毫秒
                }
            }
        }

        throw $lastException;
    }

    private function doRequest(string $url): string
    {
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL            => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT        => 30,
        ]);

        $body = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);

        if ($body === false) {
            throw new RuntimeException("请求失败: {$error}");
        }

        if (in_array($httpCode, $this->retryableStatusCodes)) {
            throw new RuntimeException(
                "可重试的 HTTP 错误,状态码: {$httpCode}"
            );
        }

        return $body;
    }
}

注意事项

常见错误码

错误码常量说明解决方案
6CURLE_COULDNT_RESOLVE_HOSTDNS 解析失败检查 URL、DNS 配置
7CURLE_COULDNT_CONNECT连接失败检查目标服务器状态
28CURLE_OPERATION_TIMEDOUT操作超时增加 timeout 值
35CURLE_SSL_CONNECT_ERRORSSL 连接错误检查证书、SSL 配置
60CURLE_SSL_CACERTCA 证书验证失败配置正确的 CA 证书
67CURLE_LOGIN_DENIED认证失败检查用户名密码

内存管理

php
<?php
declare(strict_types=1);

// 正确:手动关闭句柄
$ch = curl_init('https://example.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch); // 释放资源

// PHP 8.0+ : CurlHandle 是对象,在离开作用域时自动释放
function fetchUrl(string $url): string
{
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $result = curl_exec($ch);
    curl_close($ch);
    return $result !== false ? $result : '';
}

编码问题

php
<?php
declare(strict_types=1);

// CURLOPT_ENCODING 设置为空字符串,让 cURL 自动处理 gzip/deflate
curl_setopt($ch, CURLOPT_ENCODING, '');

// 等同于发送 Accept-Encoding: gzip, deflate, br
// cURL 会自动解压响应体

// 手动指定编码
curl_setopt($ch, CURLOPT_ENCODING, 'gzip');

最佳实践

  1. 始终检查返回值curl_exec() 在失败时返回 false
  2. 设置合理的超时:避免无限等待,通常 5~30 秒
  3. 启用 SSL 验证:生产环境必须启用 CURLOPT_SSL_VERIFYPEER
  4. 关闭连接:使用完毕后调用 curl_close() 释放资源
  5. 使用 curl_setopt_array():比多次调用 curl_setopt() 更高效
  6. 捕获响应头信息:便于调试和日志记录
  7. 使用异常处理:将错误封装到异常中,便于上层处理

下一节

继续学习:cURL 高级用法 - 并发请求、文件上传下载

参考链接