惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Tenable Blog
Last Week in AI
Last Week in AI
P
Proofpoint News Feed
Engineering at Meta
Engineering at Meta
H
Help Net Security
F
Fortinet All Blogs
MyScale Blog
MyScale Blog
宝玉的分享
宝玉的分享
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园 - 司徒正美
量子位
N
Netflix TechBlog - Medium
Apple Machine Learning Research
Apple Machine Learning Research
小众软件
小众软件
Recorded Future
Recorded Future
博客园 - 三生石上(FineUI控件)
Vercel News
Vercel News
aimingoo的专栏
aimingoo的专栏
I
InfoQ
Microsoft Security Blog
Microsoft Security Blog
Scott Helme
Scott Helme
The Last Watchdog
The Last Watchdog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
IT之家
IT之家
AI
AI
WordPress大学
WordPress大学
Security Archives - TechRepublic
Security Archives - TechRepublic
Google Online Security Blog
Google Online Security Blog
U
Unit 42
V2EX - 技术
V2EX - 技术
MongoDB | Blog
MongoDB | Blog
Schneier on Security
Schneier on Security
博客园 - Franky
H
Heimdal Security Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Jina AI
Jina AI
W
WeLiveSecurity
P
Privacy & Cybersecurity Law Blog
Cloudbric
Cloudbric
B
Blog RSS Feed
N
News | PayPal Newsroom
S
Securelist
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
I
Intezer
Hacker News - Newest:
Hacker News - Newest: "LLM"
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
博客园_首页
罗磊的独立博客
H
Hackread – Cybersecurity News, Data Breaches, AI and More
雷峰网
雷峰网

小野博客

CTF:最好的语言解密过程 狐蒂云疑似准备跑路:低价云服务器的水有多深 WeMod PRO 会员高级版脚本分享 PowerShell 执行策略被禁止解决方法 一款可以屏蔽国外广告的IP过滤评论插件 当 PCDN 来敲门:一个"小"博客的 200G 流量惊魂记 船新升级!我的“一言”系统支持一键换肤了(内附10套精美皮肤) 再续前缘:利用自建一言Api接口嫁接给typecho 给网页装个“灵魂”:我写了一个超丝滑的【一言】自建语录api 桌面工具-极光便签-随时笔记
QQ音乐播放接口:PHP逆向分析与实现
小野 · 2026-06-16 · via 小野博客
解析网页版的播放接口原理,基于实战完整实现搜索、多音质获取、流式代理播放、歌词同步等细节。

一、碎

播放接口未对外开放,却可以通过开发者工具抓取分析。

记录一下网页版播放链路的逆向分析过程,以及 从零实现一个完整播放器 的全流程,包含:

  • 歌曲搜索(支持分页)
  • 多音质播放链接获取(FLAC / 320kbps / 128kbps / AAC)
  • 流式服务端代理绕过防盗链
  • 歌词实时获取与高亮同步
  • 自定义播放器 UI

免责声明: 本文仅用于技术研究学习,请尊重音乐版权,所得数据仅限个人测试使用。


二、起点:浏览器开发者工具

网络请求

打开 https://y.qq.com/,搜索任意歌曲,按 F12 → Network 面板。点击播放后,主要关注三类请求:

请求类型接口地址用途
搜索c.y.qq.com/soso/fcgi-bin/search_for_qq_cp获取歌曲元数据
播放凭证u.y.qq.com/cgi-bin/musicu.fcg POST获取 vkey 和 CDN 地址
音频文件isure.stream.qqmusic.qq.com/*实际音频流

搜索接口

GET https://c.y.qq.com/soso/fcgi-bin/search_for_qq_cp?w=七里香&p=1&n=20&format=json&platform=h5

返回 JSONP 格式数据,关键字段:


{
  "songname": "七里香",
  "songmid": "004Z8Ihr0JIu5s",
  "singer": [{"name": "周杰伦"}],
  "albummid": "003DFRzD192KKD"
}

songmid 是每首歌的唯一标识,后续所有接口都依赖它。albummid 用于拼接专辑封面 URL。

播放凭证(vkey)接口


POST https://u.y.qq.com/cgi-bin/musicu.fcg
Content-Type: application/json

请求体:

{
  "req_0": {
    "module": "vkey.GetVkeyServer",
    "method": "CgiGetVkey",
    "param": {
      "filename": ["M500004Z8Ihr0JIu5s004Z8Ihr0JIu5s.mp3"],
      "guid": "a9444620715462ea",
      "songmid": ["004Z8Ihr0JIu5s"],
      "songtype": [0],
      "uin": "0",
      "loginflag": 1,
      "platform": "20"
    }
  },
  "comm": { "uin": 0, "format": "json", "ct": 19, "cv": 0 }
}

filename 格式规则: {音质前缀}{songmid}{songmid}.{后缀}

前缀后缀音质歌曲大小
F000.flac无损 FLAC~30MB
M800.mp3高品质 320kbps~10MB
M500.mp3标准 128kbps~4MB
C400.m4aAAC 格式~3MB

响应中关键返回结构(两种历史格式需兼容):

格式一(midurlinfo):

{
  "midurlinfo": [{"purl": "M500xxx.mp3?vkey=7D54ACE0&guid=xxx&uin=6841847"}],
  "sip": ["https://isure.stream.qqmusic.qq.com/"]
}

最终 URL = sip[0] + midurlinfo[0].purl

格式二(testfile2g):


{
  "testfile2g": "C400xxx.m4a?guid=xxx&vkey=7D54ACE0",
  "sip": ["http://aqqmusic.tc.qq.com/"]
}

最终 URL = sip[0] + testfile2g(注意 HTTP → HTTPS的转换)


三、GUID 与 Cookie

GUID 生成

GUID 是 16 位随机十六进制字符串,没有校验逻辑,每次请求可随机生成:


$guid = substr(md5(uniqid(mt_rand(), true)), 0, 16);

不同Cookie的作用

状态作用音质
无 Cookie❌ 被 CDN 拦截无法播放音乐
无会员 Cookie✅ 可试听128kbps
无会员 Cookie✅ 完整播放免费歌曲320kbps
VIP Cookie✅ 完整播放FLAC 无损

Cookie 中关键字段:uin(QQ号)、qqmusic_key(登录态密钥)。有效期暂未测试过。


四、防盗链跟快速代理

Referer检查

CDN 检查 HTTP Referer 头——只有来自 y.qq.com 的请求才被允许。浏览器 <audio> 标签无法自定义 Referer,所以需要服务端代理。

否则提示:禁止跨域访问

转发代理

传统代理使用 file_get_contents 下载完整文件后再输出,延迟大(几十秒)。优化方案是使用 fopen + fpassthru 边下载边转发


$fp = @fopen($url, 'rb', false, stream_context_create([
    'http' => ['header' => "User-Agent: Mozilla/5.0\r\nReferer: https://y.qq.com/"]
]));
if ($fp) {
    fpassthru($fp);  
    fclose($fp);
}

这样浏览器在收到第一个数据包后就可以开始缓冲播放,延迟从数十秒降到 1-3 秒。

4.3 代理流程


┌─────────┐  src="proxy.php?url=..."  ┌──────────┐  fopen+fpassthru  ┌──────────────┐
│ Browser │ ←──────────────────────── │ PHP Proxy│ ←─────────────── │ QQ Music CDN │
│         │      流式音频数据          │          │  带 Referer 请求  │              │
└─────────┘                          └──────────┘                   └──────────────┘

五、完整实现

HTTP工具


function http_get($url, $referer = 'https://y.qq.com/') {
    $ctx = stream_context_create([
        'http' => [
            'method' => 'GET',
            'header' => "User-Agent: Mozilla/5.0\r\nReferer: $referer\r\n",
            'timeout' => 10
        ],
        'ssl' => ['verify_peer' => false, 'verify_host' => false]
    ]);
    return @file_get_contents($url, false, $ctx);
}

function http_post($data, $cookie = '') {
    $json = json_encode($data);
    $header = "User-Agent: Mozilla/5.0\r\n"
            . "Referer: https://y.qq.com/\r\n"
            . "Content-Type: application/json\r\n"
            . "Content-Length: " . strlen($json);
    if ($cookie) $header .= "\r\nCookie: " . $cookie;

    $ctx = stream_context_create([
        'http' => ['method' => 'POST', 'header' => $header, 'content' => $json, 'timeout' => 8],
        'ssl' => ['verify_peer' => false, 'verify_host' => false]
    ]);
    return @file_get_contents("https://u.y.qq.com/cgi-bin/musicu.fcg", false, $ctx);
}

搜索接口实现


$kw = $_GET['w'];
$page = $_GET['p'] ?? 1;

$resp = http_get("https://c.y.qq.com/soso/fcgi-bin/search_for_qq_cp?" . http_build_query([
    'w' => $kw, 'p' => $page, 'n' => 20, 'format' => 'json',
    'platform' => 'h5', 'g_tk' => '5381', 'uin' => '0'
]));

if (preg_match('/^[A-Za-z_]+\((.*)\)$/s', $resp, $m)) $resp = $m[1];

$data = json_decode($resp, true);
$songs = $data['data']['song']['list'] ?? [];

返回的 albummid 用于拼接封面图 URL:https://y.qq.com/music/photo_new/T002R300x300M000{albummid}.jpg

不同音质的获取

每个音质独立请求 vkey 接口,按优先级排序:
从响应中提取 midurlinfo / testfile2g
构造完整播放 URL 并收集到 $urls 数组


$fmtList = [
    ['F000', '.flac',  '无损FLAC'],
    ['M800', '.mp3',   '高品质320kbps'],
    ['M500', '.mp3',   '标准128kbps'],
    ['C400', '.m4a',   'AAC'],
];

foreach ($fmtList as $fmt) {
    $body["req_0"]["param"]["filename"] = [$fmt[0] . $mid . $mid . $fmt[1]];
    $resp = http_post($body, $cookie);
    
}

歌词获取


$resp = http_get(
    "https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg?"
    . "songmid={$mid}&pcachetime=" . round(microtime(true) * 1000)
);

$d = json_decode($resp, true);
$lyricRaw = base64_decode($d['lyric']);

// 解析 LRC 格式
preg_match_all('/\[(\d{2}):(\d{2})\.(\d{2,3})\](.*)/', $lyricRaw, $m, PREG_SET_ORDER);
foreach ($m as $v) {
    $ms = intval($v[3]);
    if (strlen($v[3]) == 2) $ms *= 10;  // 2位毫秒 → 补成3位
    $lines[] = [
        't' => intval($v[1])*60 + intval($v[2]) + $ms/1000,
        'c' => trim($v[4])
    ];
}

音频代理


if ($action == 'proxy') {
    $url = $_GET['url'];
    $hdr = "User-Agent: Mozilla/5.0\r\nReferer: https://y.qq.com/";
    if ($cookie) $hdr .= "\r\nCookie: " . $cookie;

    $fp = @fopen($url, 'rb', false, stream_context_create([
        'http' => ['method' => 'GET', 'header' => $hdr, 'timeout' => 60],
        'ssl'  => ['verify_peer' => false, 'verify_host' => false]
    ]));
    if ($fp) { fpassthru($fp); fclose($fp); }
    exit;
}

六、前端实现要点

播放器ui扔给AI处理就行了

歌词同步

前端通过 ontimeupdate 事件(每 250ms)获取播放进度,匹配歌词时间戳:


audio.ontimeupdate = function() {
    var cur = audio.currentTime;

    for (var i = lyrics.length - 1; i >= 0; i--) {
        if (lyrics[i].t <= cur + 0.3) {
            lines[i].style.color = "#007aff";
            lines[i].scrollIntoView({block: "center"});
            break;
        }
    }
};

API 返回的播放链接包含 vkeyuinguid 等敏感信息,展示到调试面板前进行脱敏处理


cookies请自己F12网页登录抓取,复制整个cookies值,粘贴到下面文件的头部

本文对应完整单文件实现可在配套的 qqmusic-demo.php 查看。该文件集成了搜索、多音质获取、流式代理、歌词同步、自定义播放器等全部功能,可直接部署运行。

网盘规则,下载后删除.txt后缀

下载地址