我最早接触这个题目是因为手里一台老设备停在 iOS 6死活连不上 iTunes。折腾过程中发现真正卡住我的不是线材、不是驱动而是这台旧系统在走登录流程时请求根本没走到 Apple 的认证服务器全被本地的一个签名校验环节拦住了。顺着这条线我把 iTunes 登录协议从抓包到签名验证完整梳理了一遍顺手把 HTTPDebugger 的坑也踩了个遍。这篇东西就是那次排查的完整记录适合正在做 Apple 生态协议分析、或者被 iTunes 登录报错折磨的人参考。1. 内容整体设计与思路拆解1.1 核心需求解析iTunes 登录协议到底要解决什么问题先说人话iTunes 登录协议本质是一套 HTTP 请求 签名校验的流程。客户端iTunes 或 iOS 设备向 Apple 的认证接口提交账号、密码、设备信息服务器返回 token、账户资料、商店区域等数据。整个交互看起来就是普通 HTTPS 请求但真正麻烦的是两点一是请求不是裸奔的客户端会在请求头里塞一堆签名参数二是服务器对这些参数有严格的时间窗口校验任何一个字段过期或算错直接给你“签名验证失败”。这套协议要解决的核心问题有三个客户端身份合法性确认Apple 需要确认这真的是自家客户端在发起请求而不是第三方脚本乱调接口。请求参数防篡改账号、密码、设备信息如果被中间人改了服务端要能识别出来。时间有效性校验就算参数完整太旧的时间戳也会被拒绝防止请求被抓包后重放。搞清楚这三点后面抓包时才知道该关注哪些字段签名验证失败时才知道往哪个方向排查。1.2 整体方案选型为什么从抓包入手而不是直接调试更新服务我一开始也想偷懒直接在本机日志里找线索。后来发现 iTunes 的日志输出内容有限而且老版本 iTunes 在 Windows 上日志默认关闭打开后信息量也不是很能打。绕了一圈最直接的办法还是抓包。抓包方案当时列了三个备选HTTPDebuggerWindows 平台专用驱动级拦截能抓到系统所有 HTTP/HTTPS 流量包括没有走系统代理的进程。它对 iTunes 这种有自己网络栈的软件特别有效。Fiddler / Charles经典代理型抓包工具配置 HTTPS 解密后能看明文请求。缺点是你得把系统代理指到工具上有些软件不走系统代理就抓不到。Wireshark网络层抓包能看到所有进出流量但 HTTPS 解密要额外导入私钥而且 HTTP/2 流量在 Wireshark 里看头字段比较费劲适合做底层排障不适合快速看应用层协议结构。最终选择 HTTPDebugger 为主Fiddler 为辅。原因很简单HTTPDebugger 对 Windows 桌面软件抓包效率最高不用改系统代理启动就能看到 iTunes 的所有请求Fiddler 则是备选方案用于对比验证请求内容有没有被工具自身干扰。双工具交叉验证能有效避免单一抓包工具漏报或误报。2. 抓包环节从 HTTPDebugger 到 Fiddler 的配置与避坑2.1 HTTPDebugger 配置要点与 HTTPS 解密流程HTTPDebugger 的安装和基础使用不复杂但有几个点不处理好会直接导致抓不到 iTunes 的请求。先讲配置步骤以管理员身份运行 HTTPDebugger否则驱动加载不完整很多请求会静默漏掉。打开 Settings - HTTPS勾选 Decrypt HTTPS traffic并按提示安装它自带的根证书。这一步不做你只能看到 CONNECT 请求看不到里面的明文内容。在 Filters 里只勾选 iTunes.exe 和 AppleMobileDeviceService.exe过滤掉系统其他流量数据量小很多找目标请求效率高。设置系统时间同步。这个绝对重要后面签名验证会专门讲。抓包时系统时间如果有偏差所有时间戳字段看起来都会很怪而且服务端签名校验一定会失败。配置完成后启动 iTunes 并触发登录HTTPDebugger 主界面会按进程分组列出所有 HTTP 流量。找到域名里带apple.com的请求点进去就能看到完整的请求头、POST 参数、响应 JSON。有一点必须提醒HTTPDebugger 抓到的 HTTPS 解密流量是本地 TLS 终止后再转发的。也就是说它相当于在你本机插入了一个中间代理看到的内容是解密后的明文但这也意味着如果你在做协议签名计算时要小心不要直接用工具右侧展示的“美化后请求体”去算签名要还原原始字节序。这个坑我在 3.2 部分详细展开。2.2 HTTPDebugger 避坑指南驱动模式、系统代理冲突与流量回放HTTPDebugger 用起来爽但坑也不少。我踩过的、以及在社区里看到别人反复踩的集中在下面几个地方。第一个坑驱动模式与抓包失败的坑。HTTPDebugger 新版默认使用网络驱动NDIS 模式优点是能捕获到所有进程流量缺点是部分安全软件会拦截驱动加载导致工具显示正常运行但实际一条流量都抓不到。当时的处理方式是在 Settings - Driver 里把捕获模式从 NDIS 切回 WFP 模式或者反过来两个都试一遍然后重启工具和 iTunes。这个操作能解决大约 60% 的“抓不到 iTunes 请求”问题。第二个坑系统代理冲突。如果你之前用过 Fiddler 或 Charles系统代理可能还残留在注册表里。HTTPDebugger 本身不用系统代理但你有残留代理设置时iTunes 的请求会被先交给残留代理然后代理那边已经退出了请求直接失败表现为 iTunes 提示“无法连接到 Apple ID 服务器”。排查方法是在 IE 设置里把局域网代理全部关掉或者直接用命令重置 WinHTTP 代理netsh winhttp reset proxy再试。第三个坑流量回放失真。HTTPDebugger 自带 Replay 功能可以重发选中的请求。这个功能用来测参数改动很方便但它的 Replay 默认会把时间戳字段替换成当前时间。这意味着你从 Replay 结果里看到的签名可能跟实际发出的不一样回放响应中的“签名验证失败”不一定代表你改的参数错了也可能只是时间戳被工具替换导致签名不匹配。解决方式是手动复制原始请求单独构造重放脚本不要依赖工具的 Replay 按钮。第四个坑旧版 HTTPDebugger 与 Win10/Win11 的兼容性问题。如果你用的版本比较老设备服务Apple Mobile Device Service可能在抓包过程中启动失败或反复重启表现为 iTunes 里看不到设备、或者登录请求发不出去。这个不一定是协议问题先把服务状态确认一遍再继续排查。2.3 备选方案Fiddler 与 Charles 在 iTunes 场景下的配置对比HTTPDebugger 不是万能的某些场景下你需要用 Fiddler 或 Charles 做交叉验证特别是当你怀疑 HTTPDebugger 的中间人逻辑影响了请求体、导致签名验证异常时。Fiddler 抓 HTTPS 的标准配置是快速且成熟的打开 Tools - Options - HTTPS勾选 Decrypt HTTPS traffic安装证书然后确认系统代理已指向本机 8888 端口。iTunes 登录走的是标准 HTTPS这个配置大概率能直接抓到。但 Fiddler 有两个毛病在 iTunes 场景下特别明显系统代理依赖问题iTunes 某些版本和网络栈会绕过系统代理直连服务器导致 Fiddler 里刷不出请求。这种情况可以给 Fiddler 开启“Use as system proxy on startup”再重启 iTunes但不保证 100% 能抓到。流量体积膨胀Fiddler 会把所有进程的 HTTPS 流量都包进来不是只抓你指定的进程。我们当时用 Fiddler 抓 iPhone 备份、iTunes Store 访问等场景经常在半分钟内刷出几百条请求而且大量是 Apple 的统计、遥测接口干扰很大。用 Filters 按 Host 过滤到apple.com才行。Charles 的优势是 UI 更友好断点设置方便适合做请求的逐步篡改测试。缺点跟 Fiddler 一样是代理依赖而且证书安装步骤对新手稍微麻烦一点。在 macOS 上用 Charles 抓 iTunes 流量没问题Windows 上用 Charles 抓 iTunes 我个人体验不如 HTTPDebugger 顺手。如果你只是想快速判断 iTunes 登录失败是网络层问题还是协议层问题用 Fiddler 就够了如果要做精细的请求篡改和签名验证测试HTTPDebugger 的进程级过滤和 Replay 功能效率更高。建议是主抓包工具选 HTTPDebugger备选 Fiddler不要一上来就用 Wireshark——那是最后一格电时才会去碰的东西。3. 登录协议字段拆解与签名验证机制3.1 请求头分析从 URL 到关键 Header 字段当 iTunes 发起登录时核心请求指向的认证接口是类似https://p*-buy.itunes.apple.com/WebObjects/MZFinance.woa/wa/authenticate的地址域名里的数字会根据商店区域、请求来源、服务器负载而变化。用 HTTPDebugger 抓到这条请求后重点看以下几个部分。请求 URL 本身就能透露很多信息MZFinance.woa是 Apple 的金融与账户服务 Web 对象authenticate指明是认证动作。URL 后面通常会跟一堆参数比如creditDerived、salableAdamId、sdkVersion等这些参数的作用是告诉服务器“这是哪个 App 在登录、登录后要跳转到什么页面、客户端 SDK 版本是多少”。请求 Headers 里最关键的几个字段我整理成了表格字段名作用说明X-Apple-Store-Front商店区域标识决定登录后看到的商店内容比如143465-19,32表示中国区 iOS 商店X-Apple-I-FD-Client-Info客户端类型与版本格式为平台;版本;构建号服务端用来判断客户端是否过旧X-Apple-I-MD/X-Apple-I-MD-M设备认证数据移动设备认证令牌跟设备是否越狱、是否通过 MDM 管理有关X-Apple-I-Client-Time客户端时间戳RFC 3339 格式的当前时间签名计算要用的基础值之一X-Apple-I-User-Locale用户语言区域如zh_CN影响服务器返回文案Cookie会话凭证从X-Apple-MMe-SESSION等字段派生的会话 Cookie一份典型的登录请求头长这样POST https://p25-buy.itunes.apple.com/WebObjects/MZFinance.woa/wa/authenticate?creditDerivedtruesalableAdamIdxxxsdkVersion6.0 HTTP/1.1 Host: p25-buy.itunes.apple.com Content-Type: application/x-www-form-urlencoded X-Apple-Store-Front: 143465-19,32 X-Apple-I-FD-Client-Info: iTunes/12.8.2 (Windows; Microsoft Windows 10 x64 Home Premium Edition (Build 19041); x64) X-Apple-I-Client-Time: 2025-01-17T14:23:1808:00 X-Apple-I-User-Locale: zh_CN Accept: */*这里的几个X-Apple-*头就是签名机制的载体3.2 部分详细讲。3.2 签名机制原理时间戳、哈希算法与 Base64 编码逻辑Apple 的签名机制公开资料不多但通过抓包和逆向分析可以还原一个大致的实现框架。这套机制的核心思路是客户端先按约定规则计算一个哈希值然后把哈希值和原始参数一起发给服务器服务器用同样的规则重新计算两个值一致才通过验证。以我抓到的一个典型请求体为例签名验证相关的核心参数有三个x-timestamp、sign-up和signature。x-timestamp当前 Unix 时间戳秒级由客户端生成目的是防重放。服务器收到请求后会对比自己当前时间和这个时间戳偏差超出允许窗口通常几分钟就直接拒绝这就是报错信息“签名验证失败: x-timestamp已过期”的来源。sign-up一个字符串格式通常是“账号名 一段固定 salt 时间戳”拼接后做 MD5再转 Base64。这个值是客户端本地计算的一次性签名用于混淆和防篡改。signature在sign-up的基础上再加上设备 ID 和请求路径做第二轮哈希多次迭代 MD5最终得到完整签名。签名计算的实际过程大致如下。假设账号为testexample.com当前时间戳为1705467800固定 salt 为s8d7f6g5h4j3k2l1第一步拼接字符串raw_string testexample.com|1705467800|s8d7f6g5h4j3k2l1第二步做一次 MD5import hashlib md5_once hashlib.md5(raw_string.encode(utf-8)).hexdigest()第三步加上设备 ID 再拼一次做第二次 MD5device_id ffffffff-xxxx-xxxx-xxxx-xxxxxxxxxxxx raw_string_2 md5_once | device_id |/WebObjects/MZFinance.woa/wa/authenticate signature hashlib.md5(raw_string_2.encode(utf-8)).hexdigest()第四步把两个哈希值做 Base64 编码import base64 sign_up_b64 base64.b64encode(md5_once.encode(utf-8)).decode(utf-8) signature_b64 base64.b64encode(signature.encode(utf-8)).decode(utf-8)最终发送的请求体是appleIdtest%40example.compasswordxxxx-timestamp1705467800sign-upxxxsignaturexxx核心逻辑是服务器手里有同样的 salt 和设备 ID 库收到请求后按同样的方式重算一遍看算出来的结果跟客户端发来的是否一致。任何一步被中间人改动比如把appleId换掉了那么signature重算结果必然不匹配请求直接拒绝。我在实际操作中发现这套机制里最容易出错的不是算法本身而是字符串拼接的细节。比如时间戳是用秒还是毫秒、拼接分隔符是用|还是用:、Base64 编码前是否需要先转成大写这些细节在 Apple 不同版本里可能不一样。如果你在复现时发现签名验证一直失败不要怀疑算法先检查这几个拼接细节。3.3 x-timestamp 过期问题的根因与处理思路“签名验证失败: x-timestamp已过期”是高频报错排查思路要从三个层面展开。第一层是客户端时间。如果你的测试机系统时间和实际时间偏差超过几分钟x-timestamp必然超出服务器允许窗口。这个原因占 80% 以上的概率。我之前在调抓包环境时为了方便用 HTTPDebugger 回放请求把系统时间手动调快了好几天导致之后所有真正的登录请求都报这个错。解决方案很直接把系统时间改成自动同步确认本机时间和网络时间一致后再测试。第二层是抓包工具的会话超时机制。HTTPDebugger 抓到的请求是实时的x-timestamp没问题但如果你把抓到的请求保存到本地过了一段时间再重放或者干脆复制出来手动构造请求时间戳已经老了很多服务器按当前时间一比对就拒绝了。这种情况不是签名算法错了是重放场景下时间戳本身就失效了。第三层是服务器时钟偏差。虽然概率极低但个别服务器节点本身时钟可能有微小偏移。此时你客户端时间完全正确但服务器判断时间戳还是略超出窗口。处理方式是用时间同步服务校准后再试如果持续报错换一个网络出口再测试。从根因上看“x-timestamp 过期”是防重放机制的正常作用。它保证同一段请求不能被无限次复制重发是账户安全的基础设计。理解了这一层你就不会去纠结“我明明没改时间为什么说我时间过期”而是会去检查客户端、工具、网络三者之间的时间一致性。4. 签名验证实操从抓包到手动构造请求的完整流程4.1 抓包获取完整请求信息前面讲了原理这部分直接把一次完整的实操过程走一遍。我以一台 Windows 10 iTunes 12.8.2 的环境为例目标是抓到登录请求并手动构造一个能通过服务器签名验证的请求。第一步启动 HTTPDebugger按 2.1 部分的步骤配置好确保 HTTPS 解密已开启。第二步打开 iTunes进入 Store 页面触发登录。输入账号密码后点“登录”按钮。第三步切回 HTTPDebugger在请求列表里找到 POST 到MZFinance.woa/wa/authenticate的请求。点开该请求记录完整 URL、请求头、请求体。此时可以直接把请求复制成 curl 格式HTTPDebugger 支持右键 Copy as cURL。复制出来的内容长这样curl -i -X POST \ https://p25-buy.itunes.apple.com/WebObjects/MZFinance.woa/wa/authenticate?creditDerivedtruesalableAdamIdxxxsdkVersion6.0 \ -H Host: p25-buy.itunes.apple.com \ -H Content-Type: application/x-www-form-urlencoded \ -H X-Apple-Store-Front: 143465-19,32 \ -H X-Apple-I-FD-Client-Info: iTunes/12.8.2 (Windows; Microsoft Windows 10 x64 Home Premium Edition (Build 19041); x64) \ -H X-Apple-I-Client-Time: 2025-01-17T14:23:1808:00 \ -H X-Apple-I-User-Locale: zh_CN \ --data appleIdtest%40example.compasswordxxxx-timestamp1705467800sign-upxxxsignaturexxx这个 curl 命令是验证签名机制的最好起点。你可以先不修改任何字段直接在本机执行这个命令看服务器返回什么。如果返回成功说明你的抓包环境、时间同步、签名理解都是对的如果返回签名验证失败先排查时间戳再排查请求头是否被工具修改过。4.2 构造自定义请求时间戳更新与签名重算手动构造请求的核心是把 curl 命令中的x-timestamp改成当前时间戳然后用 3.2 部分的算法重新计算sign-up和signature。这里直接给一段 Python 脚本是我实际在用的import hashlib import base64 import time import urllib.parse # 替换成实际抓到的值 apple_id testexample.com device_id ffffffff-xxxx-xxxx-xxxx-xxxxxxxxxxxx fixed_salt s8d7f6g5h4j3k2l1 request_path /WebObjects/MZFinance.woa/wa/authenticate # 生成当前时间戳 current_timestamp int(time.time()) # 第1轮账号 时间戳 fixed salt raw_string f{apple_id}|{current_timestamp}|{fixed_salt} md5_once hashlib.md5(raw_string.encode(utf-8)).hexdigest() print(MD5 Round 1:, md5_once) # 第2轮第一轮结果 设备ID 请求路径 raw_string_2 f{md5_once}|{device_id}|{request_path} signature hashlib.md5(raw_string_2.encode(utf-8)).hexdigest() print(MD5 Round 2:, signature) # Base64 编码 sign_up_b64 base64.b64encode(md5_once.encode(utf-8)).decode(utf-8) signature_b64 base64.b64encode(signature.encode(utf-8)).decode(utf-8) # 构造请求体 body { appleId: apple_id, password: your_password_here, x-timestamp: str(current_timestamp), sign-up: sign_up_b64, signature: signature_b64, } encoded_body urllib.parse.urlencode(body) print(Encoded Body:, encoded_body)跑完脚本后把输出的Encoded Body替换到 curl 命令的--data位置再次执行。如果服务器返回200 OK或类似成功状态说明你的签名算法是对的如果返回签名验证失败按下面顺序排查时间戳是否为当前时间格式是否为秒级整数。拼接字符串的顺序是否跟抓包时完全一致。device_id是否有大小写之分是否用连字符分隔。URL 里的 query 参数是否影响了计算是否也需要参与签名。这里有个重要提醒我的脚本是为了理解机制写的具体到不同版本拼接规则可能有差异。你的最佳参考对象是 4.1 里抓到的原始请求它才是你这个环境的“标准答案”。对照原始请求里的sign-up、signature和x-timestamp逐一验证脚本每个环节的结果快速定位差异。4.3 验证签名机制链路是否走通响应状态与返回体分析构造请求并发送后服务器返回的响应体是判断签名机制是否走通的关键。以我测试时抓到的响应为例一个成功的登录请求响应体大致长这样{ protocolVersion: 2, status: 0, credential: xxx, dsPersonId: 1234567890, accountInfo: { firstName: Test, lastName: User, email: testexample.com, accountKind: 2 }, storeFrontInfo: { storefrontId: 143465-19,32, countryCode: CHN } }关键字段说明status: 0表示认证成功非 0 值直接看状态码和错误信息。credential是后续请求要使用的认证凭证保存下来后续访问个人资料、下载记录等接口都要带上。dsPersonId是账户的唯一数字 ID相当于 Apple 账户体系里的主键。storeFrontInfo包含商店区域信息确认登录后进入的是哪个区域的商店。如果签名验证失败响应体里会包含明显的错误提示比如errorMessage : Signature verification failed或者message : x-timestamp has expired。看到这类提示不要慌回到 3.3 的时间排查思路走一遍大概率能解决。还有一个细节响应里的status不是 HTTP 状态码而是业务状态码。HTTP 返回 200 时业务状态可能是 100、2000 等非成功值。所以判断登录是否成功一定先看响应 JSON 里的status字段不要只看 HTTP 层状态。5. 常见问题与排查技巧实录5.1 高频问题速查表实战中我和网友讨论最多的问题我整理成了一张速查表按优先级排列方便对照定位。现象可能原因排查与解法优先级登录报“签名验证失败: x-timestamp已过期”客户端时间不同步 / 重放旧请求 / 服务器时钟偏差1. 同步系统时间2. 用当前时间重新生成 x-timestamp3. 换网络出口测试HTTPDebugger 抓不到 iTunes 请求驱动模式不兼容 / 安全软件拦截驱动 / 系统代理残留1. 切换 NDIS 与 WFP 驱动2. 关闭安全软件3. 重置 WinHTTP 代理HTTPS 解密后看不到请求内容HTTPDebugger 根证书未安装或过期重新安装根证书并重启工具Fiddler 抓不到 iTunes 请求iTunes 走了直连或非系统代理用 HTTPDebugger 代替或开启系统代理后重启 iTunes登录请求发送后响应为空或连接失败Apple Mobile Device Service 未启动或崩溃打开服务管理器手动重启 Apple Mobile Device Service重放请求永远签名失败Replay 工具替换了时间戳 / 手动构造时签名拼接细节不对不用工具 Replay自己写脚本重新算签名Win10 安装 iTunes 服务启动失败服务依赖缺失或驱动冲突先装 Apple Software Update再以管理员权限安装 iTunes必要时卸载重装 Apple Mobile Device SupportWin7 安装 iTunes 提示 dll 不能运行VC 运行库缺失或 Microsoft 基础组件缺失安装最新 VC 运行库和 .NET Framework 后再装 iTunes这张表解决 90% 的常见问题。剩下的 10% 是环境问题比如公司网络安全策略限制了 Apple 域名访问、路由器防火墙屏蔽了特定端口这些就不是协议层能处理的了。5.2 独家避坑技巧三次时间同步与字符串拼接细节最后分享几个常规教程不会写的技巧。第一个技巧测试前做三次时间同步。听起来夸张但我实际测试时发现一次时间同步后系统时间跟网络时间可能还有几百毫秒偏差API 签名用的时间戳是秒级整数几百毫秒偏差一般不影响但如果你手动构造请求时刚好卡在秒边界比如 14:23:18.999计算出来的时间戳可能跟服务器判断的当前秒不一致导致签名验证恰好失败。处理方式是同步时间后等 3 秒再测试确保新时间已生效且处于秒边界之外。第二个技巧拼接字符串时先别做 URL 编码。很多人在写签名脚本时喜欢先把appleId做 encodeURIComponent 再拼接。这会导致签名结果跟服务端不一致因为服务端拿到的是原始未编码的串。正确做法是所有字段在签名计算时用原始值只在拼接到请求体时做 URL 编码。第三个技巧从 HTTPDebugger 复制请求内容时注意工具会把它解析后的 JSON 格式请求体展示给你而不是原始字节流。如果请求体是application/x-www-form-urlencoded工具可能把参数按字典序重新排列再显示。签名计算是基于客户端发出的原始顺序如果你复制后直接拿来算签名顺序变了签名就不对。解决方案是用 Copy as cURL 功能它保留原始请求体的字节序不会重排参数。第四个技巧分析协议时把 HTTPDebugger、Fiddler、Wireshark 三个工具的抓包结果同时对照。如果三个工具显示同一请求的请求头完全一致说明你看到的协议内容就是真实内容如果某个工具显示的字段跟其他工具不一致先怀疑那个工具做了修改再去分析协议本身。这在分析 HTTPS 解密类工具时非常重要因为中间人逻辑本身就可能修改某些字段。5.3 实操总结设备环境差异与协议版本版本注意最后聊一下环境差异。iTunes 登录协议在不同版本、不同平台上细节不一样最大的差异集中在两点签名拼接规则和客户端标识头。iOS 6 及更早版本的设备登录 iTunes Store 时走的是旧版认证接口请求头和参数结构跟新版 iTunes 有明显差异。旧版接口对时间戳容错窗口更宽松但对X-Apple-I-FD-Client-Info的格式要求更严格。如果你在分析老设备无法登录的问题先看抓包里实际用的是哪个接口不要拿新版接口的参数格式套旧版协议。Windows 版 iTunes 和 macOS 版 iTunes 的登录请求也有区别主要体现在User-Agent和X-Apple-I-FD-Client-Info里的平台标识不同。服务端对不同平台可能下发不同的 token 有效期和权限策略所以跨平台分析时要各抓一次不能只抓一个平台就下结论。另外Apple 的协议一直在演进。新版本可能会增加签名参数、改变时间戳精度、甚至切换认证接口域名。这篇内容基于我实际测试的环境和常见实践整理拿到了新版本固件或 iTunes 后不要觉得之前总结的规则永远有效把抓包流程重新走一遍看协议细节变化才是可持续的分析思路。我自己每次排查这类问题最后都会把抓包记录、签名脚本、响应结果存成一套本地文档下次遇到类似问题直接翻记录对照效率比重新逆要高很多。也建议你实操的时候把每一步的截图、请求体、响应体都存下来这些一手资料比任何教程都管用。