微信生态里经常见到 url.cn 开头的短链接,点开后会经过一次或多次跳转才到达真实页面。如果想在服务器端用 PHP 批量获取真实地址,仅靠肉眼点击不够,需要结合浏览器开发者工具看清跳转过程,再用代码复现请求逻辑。

一、为什么微信短链接不能直接还原
微信短链接服务本质是一个重定向中枢。当用户访问 url.cn 某串字符时,微信服务器先校验来源与环境,再返回 302 状态码和 Location 头。如果请求头里缺少正常浏览器特征,或者没有带上微信内特有的上下文参数,就会被拦下或跳到错误页。
很多新手以为用 file_get_contents 读一下短链就能拿到内容,结果只得到一句话的跳转提示。这是因为 PHP 默认不跟随 Location,且发出的请求头过于简单,被微信识别为非浏览器客户端。要还原,就必须先弄明白浏览器里到底发了什么。
二、用浏览器开发者工具抓包看真实跳转
在电脑版微信里把短链甩到默认浏览器打开,按 F12 切到网络面板,勾选保留日志。刷新页面后,你能看到第一条 url.cn 请求,状态 302,响应头里写着 Location 指向某个长链接。有时这个长链接还会再跳一次,比如跳到 mp.weixin.qq.com 的具体文章页。
把这几条请求的请求头展开,重点看 User-Agent、Referer 以及 Cookie。你会发现微信浏览器里的 UA 带有 MicroMessenger 字样,而普通 Chrome 打开时 UA 不同,偶尔会导致 Location 给的是下载页而非内容页。抓包的意义就在于抄下这些头信息,让 PHP 伪装得像微信内部浏览器。
2.1 记录关键请求头
不需要全部头都带,一般复制以下三项即可:User-Agent 填微信版;Referer 填 https://ipipp.com 或微信域名;Cookie 若有微信会话态也可带上。这样 PHP 发出去的请求和浏览器在微信里发的就很接近。
另外注意,有的短链跳转带签名参数,例如 ?sign=xxx,这个 sign 是服务端按时间生成的,抓包当次有效。所以别指望存下 sign 复用,而是每次都用 PHP 实时请求短链去拿最新 Location。
三、PHP 递归跟随重定向还原地址
CURL 是 PHP 里处理跳转最方便的工具。我们关闭自动跳转,手动读取响应头里的 Location,循环请求直到没有 302 或 301,就能拼出真实地址。下面示例演示了基础实现。
<?php
function resolveWechatShortUrl($shortUrl) {
$url = $shortUrl;
$maxRedirect = 5;
$ch = curl_init();
// 伪造微信浏览器请求头
$headers = array(
'User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.20',
'Referer: https://ipipp.com',
'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
);
for ($i = 0; $i < $maxRedirect; $i++) {
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
$resp = curl_exec($ch);
if ($resp === false) {
break;
}
// 从响应头提取状态码与Location
preg_match('/HTTP/d.ds+(d+)/', $resp, $codeMatch);
$code = isset($codeMatch[1]) ? (int)$codeMatch[1] : 0;
if ($code == 301 || $code == 302) {
preg_match('/Location:s*(.+)r/i', $resp, $locMatch);
if (isset($locMatch[1])) {
$url = trim($locMatch[1]);
continue;
}
}
break;
}
curl_close($ch);
return $url;
}
$real = resolveWechatShortUrl('https://url.cn/abcdef');
echo $real;
?>
3.1 代码原理说明
上面函数每次只发 HEAD 请求,节省带宽。CURLOPT_FOLLOWLOCATION 设为 false 是为了自己控制跳转,避免 CURL 内部跟随时丢掉了我们设置的微信 UA。正则从原始响应头里抠出 Location,拼成下一次请求的 URL。
如果短链跳到了带微信登录态的页面,HEAD 可能返回 403,此时可改 CURLOPT_NOBODY 为 false 发 GET,并补上抓包看到的 Cookie。但普通文章页一般 HEAD 就能拿到最终地址。
四、前端抓包与后端解析的配合方式
有人问,既然浏览器开发者工具能看到真实地址,直接复制不就行了?确实手动可以,但面对每天几千条推广短链,人工点开不现实。正确做法是:先用浏览器对任意一条短链抓包,确认微信的跳转规律和所需头;再把规律写进 PHP 脚本,以后丢短链进脚本就出长链。
这种配合把浏览器当探针、PHP 当执行器,既绕开了微信网页端的反爬,又实现了自动化。比起纯 JS 在页面里解析,PHP 服务端拿到的地址可以直接进数据库,供业务系统调用。
五、常见误区与规避
误区一是以为短链背后是固定映射,存一次长链永久用。实际上微信可能按访问频度换签名,旧长链会失效。误区二是过度依赖 FOLLOWLOCATION,结果 CURL 用默认 UA 跳完,得到的是 pc 端页面而非微信端页面,解析出的内容字段不对。
规避手段就是每次实时解析、带着微信 UA、限制跳转层数防止死循环。若批量跑时碰到封 IP,可在代码里加随机暂停,或把短链分批用不同服务器解析。
六、小结
还原微信短链接并不神秘,核心是先通过浏览器开发者工具看清重定向链路与请求头,再用 PHP 的 CURL 手动模拟同款请求并递归取 Location。掌握这个方法,无论是公众号文章、活动页还是小程序中转页,都能在服务端稳定拿到真实地址,为后续数据采集或跳转统计打好基础。