php curl 默认不跟随302重定向,需显式设置curlopt_followlocation为true,并注意open_basedir限制、手动解析location头、使用guzzle等更稳妥方案。

PHP cURL 默认不跟随 302 重定向
cURL 在 PHP 中默认关闭自动跳转,CURLOPT_FOLLOWLOCATION 是禁用状态。这意味着发起请求后,即使服务器返回 302 Found,cURL 也不会自动请求新 Location 头里的地址,而是直接返回跳转响应体(通常是空或一段 HTML),你拿到的不是目标页面内容。
解决方法是显式开启跳转支持,并注意关联限制:
- 必须同时设置
CURLOPT_FOLLOWLOCATION为true - 若启用了
open_basedir或safe_mode(已废弃但某些旧环境仍有影响),CURLOPT_FOLLOWLOCATION会被强制禁用,此时只能手动解析Location头并递归请求 - 建议搭配
CURLOPT_MAXREDIRS限制跳转次数,防止循环重定向(如 A→B→A)
手动处理 302 响应头中的 Location
当无法启用 CURLOPT_FOLLOWLOCATION(例如共享主机禁用该选项),就得自己读响应头、提取 Location、再发新请求。关键点在于分离响应头与响应体,并避免被压缩或 chunked 编码干扰:
- 务必设置
CURLOPT_HEADER为true,让 cURL 返回头+体混合内容 - 用
strpos($response, "\r\n\r\n")或正则匹配/\r\n\r\n/分割头与体,不要依赖get_headers()—— 它不经过 cURL 的实际传输过程,可能拿不到真实跳转头 - 从头部分用
preg_match('/Location:\s*(.+)/i', $headers, $matches)提取跳转地址,注意 trim 空格和换行 - 跳转地址可能是相对路径(如
/login?next=/admin),需用dirname($url) . '/' . $location或http_build_url()(PECL 扩展)补全为绝对 URL
使用 Guzzle HTTP 客户端更稳妥
Guzzle 默认开启重定向跟随,且自动处理相对 Location、跳转次数限制、Cookie 透传等细节,比裸 cURL 更少出错:
立即学习“PHP免费学习笔记(深入)”;
- 安装:
composer require guzzlehttp/guzzle - 基础用法:
$client->get($url, ['allow_redirects' => true]),其中allow_redirects可设为布尔值或数组(含max、strict、referer等键) - 注意:若目标站对
Referer敏感,Guzzle 默认不携带,可加'headers' => ['Referer' => $url]模拟来源 - 跳转过程中 Cookie 默认跨域丢失,如需保持会话,确保
allow_redirects['track_redirects']开启并检查Set-Cookie是否被正确解析
重定向链中 Cookie 和 Referer 的行为差异
不同客户端对跳转时的请求头继承策略不同,这直接影响登录态或权限校验类页面的抓取结果:
- cURL 开启
CURLOPT_FOLLOWLOCATION后,Cookie会自动带上(前提是之前设置了CURLOPT_COOKIEJAR或CURLOPT_COOKIEFILE),但Referer不会自动设为上一跳 URL —— 需手动在每次请求前设置CURLOPT_REFERER - Guzzle 默认不发送
Referer,也不自动把上一跳 URL 当作当前跳转的Referer;若需模拟浏览器行为,必须显式配置allow_redirects['referer'] = true - 某些站点(如微信 OAuth 回调)严格校验
Referer或跳转链完整性,此时手动实现跳转比依赖自动跟随更可控
重定向看着只是换个 URL,但 Cookie 生命周期、Referer 链路、相对路径解析、跳转深度限制这些细节,任何一个没对齐都可能导致“明明跳了却拿不到数据”。别只盯着 302 状态码本身。











