[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"blog-strapi-article:zh:git-clone-slow-proxy-repository-protocol-diagnosis":3,"blog-article:\u002Fblog\u002Fgit-clone-slow-proxy-repository-protocol-diagnosis":1084,"blog-related:\u002Fblog\u002Fgit-clone-slow-proxy-repository-protocol-diagnosis":1085,"blog-translations:\u002Fblog\u002Fgit-clone-slow-proxy-repository-protocol-diagnosis":1086},{"available":4,"article":5,"relatedArticles":291,"translations":884},true,{"source":6,"id":7,"documentId":8,"translationKey":8,"locale":9,"slug":10,"path":11,"_path":11,"title":12,"description":13,"excerpt":13,"image":14,"publishedAt":15,"updatedAt":16,"author":17,"tags":18,"featured":19,"sortOrder":20,"readingTime":21,"bodyType":22,"bodyBlocks":23,"bodyHtml":290},"strapi",3894,"vkahpc5jjd98znyiua0xhimo","zh","git-clone-slow-proxy-repository-protocol-diagnosis","\u002Fblog\u002Fgit-clone-slow-proxy-repository-protocol-diagnosis","Git Clone 速度变慢时，如何判断是代理、仓库还是协议的问题","Git Clone 变慢时，如何判断问题来自代理链路、仓库还是协议？本文用分阶段计时和控制变量的对照缩小排查范围，不靠主观感受判断。","https:\u002F\u002Fcms.quanqiudaili.com\u002Fuploads\u002Flarge_Git_Clone_cover_72566b8c95.webp","2026-11-03T03:00:15.196Z","2026-11-03T03:00:15.176Z","Global Proxies Team",[],false,0,3,"blocks",[24,30,36,40,61,65,69,73,77,81,95,99,117,121,125,139,143,147,151,169,173,177,189,193,197,207,211,215,219,245,255,259,266,270,276,280,286],{"type":25,"children":26},"paragraph",[27],{"text":28,"type":29},"Git 变慢往往不是“网速不够”，而是卡在某一阶段。正确做法是固定仓库、客户端、协议、缓存和时间，用 Git 自带的跟踪开关分段计时，再对照代理 IP 链路、仓库限速和协议版本三种原因。测试使用公开仓库与自有环境，不对目标仓库发起高频重复克隆。","text",{"type":31,"level":32,"children":33},"heading",2,[34],{"text":35,"type":29},"Clone 变慢时，先排查哪些因素？",{"type":25,"children":37},[38],{"text":39,"type":29},"先固定影响耗时的条件，后续对照才有意义：",{"type":41,"format":42,"children":43},"list","unordered",[44,49,53,57],{"type":45,"children":46},"list-item",[47],{"text":48,"type":29},"仓库：同一 URL、同一分支、同一提交历史；",{"type":45,"children":50},[51],{"text":52,"type":29},"客户端：Git 版本、配置、是否启用稀疏检出；",{"type":45,"children":54},[55],{"text":56,"type":29},"协议：HTTP(S) 还是 SSH，协议版本 v0\u002Fv1\u002Fv2；",{"type":45,"children":58},[59],{"text":60,"type":29},"缓存：本机对象库、DNS 缓存、代理缓存。",{"type":25,"children":62},[63],{"text":64,"type":29},"第一次克隆和后续操作的时间可能受本地或服务端缓存影响，不能直接对比。已有工作区执行 fetch、使用 `--reference`\u002Falternates、共享对象库或特定本地 clone 方式时，Git 才可能复用已有对象。对远端 URL 在独立空目录执行普通 clone，不会仅因其他目录有同仓库就自动借用其对象；记录命令、目标目录与 reference 配置，并区分客户端、服务端和代理缓存。",{"type":31,"level":32,"children":66},[67],{"text":68,"type":29},"怎么用 Git 日志找出耗时阶段？",{"type":25,"children":70},[71],{"text":72,"type":29},"用 Git 跟踪日志观察各阶段，并给输出加时间戳：",{"type":25,"children":74},[75],{"text":76,"type":29},"```bash\nGIT_TRACE=1 GIT_TRACE_PERFORMANCE=1 GIT_TRACE_CURL=1 GIT_TRACE_CURL_NO_DATA=1 \\\ngit clone \u003Curl> 2>&1 | while IFS= read -r line; do printf '%s %s\\n' \"$(date +%H:%M:%S)\" \"$line\"; done\n```",{"type":25,"children":78},[79],{"text":80,"type":29},"默认的 `GIT_TRACE_CURL` 可能记录收发数据及请求\u002F响应头；`GIT_TRACE_CURL_NO_DATA=1` 可避免记录传输正文，但仍可能暴露认证信息、Cookie、私有仓库 URL、查询参数和内部主机名。只在测试凭据与可分享仓库上使用；限制日志访问，分享前脱敏。发生凭据泄露时按流程轮换。该 trace 不提供 TCP 重传证据。",{"type":41,"format":42,"children":82},[83,87,91],{"type":45,"children":84},[85],{"text":86,"type":29},"`GIT_TRACE=1` 显示执行的子命令与阶段；",{"type":45,"children":88},[89],{"text":90,"type":29},"`GIT_TRACE_PERFORMANCE=1` 输出各阶段耗时；",{"type":45,"children":92},[93],{"text":94,"type":29},"`GIT_TRACE_CURL=1` 提供 Git 使用的 HTTP 层诊断信息；它不等于完整网络抓包，也不能据此测量 TCP 重传。",{"type":25,"children":96},[97],{"text":98,"type":29},"读日志时依次看建连\u002FTLS、引用协商和 packfile 接收阶段，不要只比较总时长。",{"type":41,"format":42,"children":100},[101,105,109,113],{"type":45,"children":102},[103],{"text":104,"type":29},"阶段：建连与 TLS ｜ 在输出里怎么认：出现 `Connected to`、TLS 握手相关行 ｜ 变慢时先查什么：代理网络路径、出口质量、DNS",{"type":45,"children":106},[107],{"text":108,"type":29},"阶段：引用协商 ｜ 在输出里怎么认：`advertise refs`、`ls-remote` 相关行 ｜ 变慢时先查什么：引用数量、协议版本、服务端处理",{"type":45,"children":110},[111],{"text":112,"type":29},"阶段：接收对象 ｜ 在输出里怎么认：`Receiving objects` 进度 ｜ 变慢时先查什么：packfile 接收阶段的字节数、速率与耗时",{"type":45,"children":114},[115],{"text":116,"type":29},"阶段：解包与检出 ｜ 在输出里怎么认：`Resolving deltas`、`Checking out files` ｜ 变慢时先查什么：本机 CPU、磁盘或文件数量；与网络接收分开计时",{"type":31,"level":32,"children":118},[119],{"text":120,"type":29},"怎么判断时间花在对象协商还是文件传输？",{"type":25,"children":122},[123],{"text":124,"type":29},"协商耗时受引用、协议和服务端处理影响；先看阶段数据，再判断是否与传输带宽有关。",{"type":41,"format":42,"children":126},[127,131,135],{"type":45,"children":128},[129],{"text":130,"type":29},"引用数量极多：`ls-remote` 与 advertise refs 阶段变慢；",{"type":45,"children":132},[133],{"text":134,"type":29},"历史极深：需要传输的 packfile 更大；",{"type":45,"children":136},[137],{"text":138,"type":29},"大文件多：单个对象大，分块与重传影响明显。",{"type":25,"children":140},[141],{"text":142,"type":29},"如果建连快而协商耗时长，先结合实际协议、过滤能力、协商请求与服务端处理复测；若接收阶段速率稳定但慢，再比较链路、平台限速和字节量。`git ls-remote \u003Curl> | wc -l` 只能粗略估计引用规模，不能用“上万行”作为通用阈值，也不能据此断言升带宽无效。每次只改一个变量，记录协商耗时、响应字节和客户端\u002F服务端情况。",{"type":31,"level":32,"children":144},[145],{"text":146,"type":29},"怎么区分代理链路、仓库限速和协议影响？",{"type":25,"children":148},[149],{"text":150,"type":29},"上一节用于判断时间落在协商还是对象传输；下表把观测现象对应到下一项对照。",{"type":41,"format":42,"children":152},[153,157,161,165],{"type":45,"children":154},[155],{"text":156,"type":29},"现象（只是线索）：建连或 TLS 阶段就慢 ｜ 待验证的假设：代理网络路径 ｜ 验证方式：换出口复测",{"type":45,"children":158},[159],{"text":160,"type":29},"现象（只是线索）：传输阶段速度稳定在某个上限 ｜ 待验证的假设：仓库或平台限速 ｜ 验证方式：同仓库不同时段、不同出口对比",{"type":45,"children":162},[163],{"text":164,"type":29},"现象（只是线索）：协商阶段请求次数异常多 ｜ 待验证的假设：协议版本或配置 ｜ 验证方式：切换 v1\u002Fv2、加 `-c protocol.version=2`",{"type":45,"children":166},[167],{"text":168,"type":29},"现象（只是线索）：起初快、中途频繁停顿 ｜ 待验证的假设：链路抖动、服务端等待或本地处理 ｜ 验证方式：对照 Git 阶段耗时、接收速率及本机 CPU\u002F磁盘；重传需独立网络证据",{"type":25,"children":170},[171],{"text":172,"type":29},"这些现象只是线索，不是结论。同一仓库、同一提交、同一客户端、同一缓存状态下多轮测试，记录阶段耗时、传输字节量、速率分布和响应头，再决定往哪个方向归因。",{"type":25,"children":174},[175],{"text":176,"type":29},"传输速率长期稳定在某一水平时，可检查仓库侧整形、带宽上限或并发限制；速率波动时则同时核对链路、服务端等待与本地解包。单次曲线不能区分这些原因，应在同一仓库和客户端条件下跨时段或出口重复测试，并记录对应阶段数据。不同出口的耗时差异只能说明结果与出口\u002F路径相关，仍需分段证据定位。",{"type":25,"children":178},[179,181,187],{"text":180,"type":29},"若表现为地区依赖或链路不可用，可参考",{"text":182,"type":29,"marks":183},"某地区依赖服务不可用时，如何验证 SaaS 产品的降级与恢复？",[184],{"href":185,"type":186},"https:\u002F\u002Fwww.quanqiudaili.com\u002Fblog\u002Fsaas-regional-fallback-testing","link",{"text":188,"type":29},"。",{"type":31,"level":32,"children":190},[191],{"text":192,"type":29},"怎么用 HTTPS、SSH 和浅克隆做对照？",{"type":25,"children":194},[195],{"text":196,"type":29},"协议、深度和过滤是三种独立对照，每次只改变其中一项：",{"type":41,"format":42,"children":198},[199,203],{"type":45,"children":200},[201],{"text":202,"type":29},"协议对照：同一仓库分别用 HTTPS 与 SSH 克隆。如果 HTTPS 走代理而 SSH 直连，两者耗时差异可能来自代理路径，也可能来自协议、认证或服务端处理差异，需结合分阶段记录判断。",{"type":45,"children":204},[205],{"text":206,"type":29},"深度对照：加 `--depth 1`。浅克隆明显变快，说明减少传输对象可能改善耗时；这不能单独排除链路因素。",{"type":25,"children":208},[209],{"text":210,"type":29},"再加一个 `--filter=blob:none` 的部分克隆对照，可进一步区分对象数量与对象体积的影响。三种对照按“协议 → 深度 → 过滤”的顺序做，每做一次只改一个变量。",{"type":31,"level":32,"children":212},[213],{"text":214,"type":29},"根据对照结果，下一步先检查什么？",{"type":25,"children":216},[217],{"text":218,"type":29},"结合前面各项对照结果，选择下一步核查：",{"type":41,"format":42,"children":220},[221,225,229,233,237,241],{"type":45,"children":222},[223],{"text":224,"type":29},"观察结果：建连或 TLS 慢 ｜ 优先排查项：代理网络路径、出口质量、DNS ｜ 下一条对照：同仓库换出口、换时段各跑一轮",{"type":45,"children":226},[227],{"text":228,"type":29},"观察结果：协商慢 ｜ 优先排查项：仓库规模、协议版本或服务端处理 ｜ 下一条对照：对照协议、协商耗时、响应字节与服务端资料",{"type":45,"children":230},[231],{"text":232,"type":29},"观察结果：packfile 慢、速率平稳 ｜ 优先排查项：平台限速或带宽上限 ｜ 下一条对照：同仓库不同时段、不同出口对比速率曲线",{"type":45,"children":234},[235],{"text":236,"type":29},"观察结果：起初快、中途停顿 ｜ 优先排查项：链路抖动、服务端等待或本地解包 ｜ 下一条对照：对照传输速率、Git 阶段与本机资源；重传需独立网络证据",{"type":45,"children":238},[239],{"text":240,"type":29},"观察结果：加 `--depth 1` 明显变快 ｜ 优先排查项：传输对象量 ｜ 下一条对照：再加 `--filter=blob:none` 对照",{"type":45,"children":242},[243],{"text":244,"type":29},"观察结果：三种对照都无差异 ｜ 优先排查项：本地磁盘、杀毒扫描、Git 并发 ｜ 下一条对照：结合本机资源监控确认",{"type":25,"children":246},[247,249,254],{"text":248,"type":29},"浅克隆后耗时下降，先确认传输对象量、仓库状态和本地缓存条件一致，再判断减少的数据量是否解释了差异。Git 命令和配置细节可查",{"text":250,"type":29,"marks":251},"Git 官方文档",[252],{"href":253,"type":186},"https:\u002F\u002Fgit-scm.com\u002Fdocs\u002Fgit",{"text":188,"type":29},{"type":31,"level":32,"children":256},[257],{"text":258,"type":29},"FAQ",{"type":25,"children":260},[261],{"text":262,"type":29,"marks":263},"Q：浅克隆更快，能证明代理链路有问题吗？",[264],{"type":265},"bold",{"type":25,"children":267},[268],{"text":269,"type":29},"A：不能，它改变了传输数据量；只能说明负载规模影响结果，需结合分阶段计时判断。",{"type":25,"children":271},[272],{"text":273,"type":29,"marks":274},"Q：SSH 和 HTTPS 速度不同，哪种结果可信？",[275],{"type":265},{"type":25,"children":277},[278],{"text":279,"type":29},"A：两者路径和认证机制不同，应分别记录，不把单次差异视为代理性能结论。",{"type":25,"children":281},[282],{"text":283,"type":29,"marks":284},"Q：公开仓库和私有仓库能放在同一组对照里吗？",[285],{"type":265},{"type":25,"children":287},[288],{"text":289,"type":29},"A：不建议，权限、服务端策略和仓库规模都会改变传输条件。","",[292,481,657],{"source":6,"id":293,"documentId":294,"translationKey":294,"locale":9,"slug":295,"path":296,"_path":296,"title":297,"description":298,"excerpt":298,"image":299,"publishedAt":300,"updatedAt":301,"author":17,"tags":302,"featured":19,"sortOrder":20,"readingTime":32,"bodyType":22,"bodyBlocks":303,"bodyHtml":290},3897,"y568ae3jjjs4yuaunluzwsqs","ai-api-egress-region-network-policy-diagnosis","\u002Fblog\u002Fai-api-egress-region-network-policy-diagnosis","测试 AI API 地区切换时，如何判断变化来自网络还是服务策略","切换代理 IP 出口地区后结果变化，如何区分网络与服务策略？本文用配对测试对照链路耗时、出口身份和服务端响应，避免把地区差异当成故障。","https:\u002F\u002Fcms.quanqiudaili.com\u002Fuploads\u002Flarge_AI_API_cover_0df5f0b27f.webp","2026-11-03T03:01:09.178Z","2026-11-03T03:01:09.154Z",[],[304,308,312,316,330,334,338,342,346,350,354,358,362,366,376,380,384,394,398,402,420,424,438,448,451,457,461,467,471,477],{"type":25,"children":305},[306],{"text":307,"type":29},"换地区之后结果变了，可能是链路、出口身份或服务策略，三者要分开取证。做法是固定请求只改地区，用分阶段耗时、IP 画像和响应证据各查一层。换地区这一步通常由代理 IP 完成，所以“换了地区”和“换了 IP”要当成两个变量记录。测试限制在自有账号和测试额度内，不通过反复请求真实付费接口制造样本。",{"type":31,"level":32,"children":309},[310],{"text":311,"type":29},"地区切换后，哪些因素可能导致结果变化？",{"type":25,"children":313},[314],{"text":315,"type":29},"地区切换可能同时改变链路、出口身份和服务策略相关条件；测试时分别记录这三类证据。",{"type":41,"format":42,"children":317},[318,322,326],{"type":45,"children":319},[320],{"text":321,"type":29},"链路质量：RTT、丢包、TLS 握手、首字节时间。",{"type":45,"children":323},[324],{"text":325,"type":29},"出口身份：IP 归属、ASN、IP 类型与信誉。",{"type":45,"children":327},[328],{"text":329,"type":29},"服务策略：限流、地区可用性、账号权限、模型可用列表。",{"type":25,"children":331},[332],{"text":333,"type":29},"如果同时换地区、出口和请求条件，结果无法区分来自哪项变化，因此对照时每轮只改变一个目标变量。",{"type":31,"level":32,"children":335},[336],{"text":337,"type":29},"怎么设计只改变出口地区的对照测试？",{"type":25,"children":339},[340],{"text":341,"type":29},"固定模型、prompt、客户端、超时和重试；按测试目的只改变地区或出口，并记录实际命中的版本和时间。",{"type":25,"children":343},[344],{"text":345,"type":29},"请求次数与观察时段应按接口波动和测试预算设定；尽量在相近时间重复对照，并避免用单次结果判断地区策略。",{"type":25,"children":347},[348],{"text":349,"type":29},"对照组至少三组：原地区、目标地区、以及目标地区的第二个出口 IP。第二组用来区分“地区本身”和“这个 IP”。",{"type":31,"level":32,"children":351},[352],{"text":353,"type":29},"怎么从 DNS、连接和响应耗时判断网络问题？",{"type":25,"children":355},[356],{"text":357,"type":29},"用 curl 对照时，必须显式使用与被测 API 相同的代理、绕过和凭据配置；凭据应从受限环境注入，不写进命令历史。下列字段是从请求开始累计的时间里程碑，不是独立 TCP\u002FTLS 耗时。代理 CONNECT、代理侧 DNS、连接复用和重定向都会影响解释；跳过的阶段标记为未观测。",{"type":25,"children":359},[360],{"text":361,"type":29},"```bash\ncurl -o \u002Fdev\u002Fnull -s -x \"$PROXY_URL\" -w 'namelookup_cumulative=%{time_namelookup} connect_cumulative=%{time_connect} appconnect_cumulative=%{time_appconnect} ttfb_cumulative=%{time_starttransfer}\\n' \\\nhttps:\u002F\u002Fapi.example.com\u002Fv1\u002Fmodels\n```",{"type":25,"children":363},[364],{"text":365,"type":29},"固定客户端、目标接口和时间窗口建立自身基线，再比较阶段分布；样本不足时只记录现象。`time_connect` 与 `time_appconnect` 不能直接当作到源站的独立 TCP\u002FTLS 时长。首字节慢也可能来自上游处理。",{"type":25,"children":367},[368,370,375],{"text":369,"type":29},"若要建立可比较的地区延迟基线，可参考",{"text":371,"type":29,"marks":372},"SaaS API 地区延迟基线怎么建？请求口径与分位数",[373],{"href":374,"type":186},"https:\u002F\u002Fwww.quanqiudaili.com\u002Fblog\u002Fsaas-api-region-latency-baseline",{"text":188,"type":29},{"type":31,"level":32,"children":377},[378],{"text":379,"type":29},"怎么确认出口 IP 的地区和类型？",{"type":25,"children":381},[382],{"text":383,"type":29},"对照多个 IP 数据库与目标服务看到的源 IP\u002F地区标签，并记录来源和查询时间。ASN、组织、城市和 IP 类型标签只能提供线索，不能单独证明出口的物理所在地或住宅\u002F机房属性；平台地区识别、购买地区与物理位置应分开记录。",{"type":25,"children":385},[386,388,393],{"text":387,"type":29},"同一地区用第二个出口复测。结果变化只说明出口或路径相关因素可能参与；固定账号、请求和时间窗口重复对照，再结合链路与服务端证据判断。来源冲突时标记为不确定。相关归因思路可参考",{"text":389,"type":29,"marks":390},"多地区测试发现问题，如何判断是网络故障还是产品缺陷？",[391],{"href":392,"type":186},"https:\u002F\u002Fwww.quanqiudaili.com\u002Fblog\u002Fregional-network-vs-product-defect",{"text":188,"type":29},{"type":31,"level":32,"children":395},[396],{"text":397,"type":29},"哪些响应信息能提示账号或地区策略限制？",{"type":25,"children":399},[400],{"text":401,"type":29},"结合错误体、限流头、账号\u002F模型可用范围和传输记录判断；即使链路不稳定，有明确来源的服务端错误仍可作为证据，但不应单独结束排查。下表列出可继续核验的线索：",{"type":41,"format":42,"children":403},[404,408,412,416],{"type":45,"children":405},[406],{"text":407,"type":29},"证据：429 与 Retry-After ｜ 候选方向：限流或配额 ｜ 下一步核对：查限流头、控制台用量及重复样本",{"type":45,"children":409},[410],{"text":411,"type":29},"证据：403 与地区或模型提示 ｜ 候选方向：可用范围 ｜ 下一步核对：核对服务方文档、账号和模型配置",{"type":45,"children":413},[414],{"text":415,"type":29},"证据：request ID 与限流 header ｜ 候选方向：服务端处理 ｜ 下一步核对：按服务方定义与网关日志核验",{"type":45,"children":417},[418],{"text":419,"type":29},"证据：链路指标稳定但持续失败 ｜ 候选方向：服务策略候选 ｜ 下一步核对：重复请求并核对错误体和账号范围",{"type":31,"level":32,"children":421},[422],{"text":423,"type":29},"确认原因后，下一步分别怎么处理？",{"type":41,"format":42,"children":425},[426,430,434],{"type":45,"children":427},[428],{"text":429,"type":29},"候选方向：链路异常 ｜ 对应证据：阶段耗时反复偏离自身基线 ｜ 下一步动作：换路径或时段复测，再看服务端响应",{"type":45,"children":431},[432],{"text":433,"type":29},"候选方向：出口相关 ｜ 对应证据：固定其余条件后结果随出口变化 ｜ 下一步动作：增加配对样本，核对路径与出口来源",{"type":45,"children":435},[436],{"text":437,"type":29},"候选方向：服务策略候选 ｜ 对应证据：错误体、账号\u002F模型范围和重复样本相互吻合 ｜ 下一步动作：核对配置或向服务方确认",{"type":25,"children":439},[440,442,447],{"text":441,"type":29},"证据不一致时，记录缺少的对照条件并保持未决。curl 参数和时间字段的含义可查",{"text":443,"type":29,"marks":444},"curl 手册",[445],{"href":446,"type":186},"https:\u002F\u002Fcurl.se\u002Fdocs\u002Fmanpage.html",{"text":188,"type":29},{"type":31,"level":32,"children":449},[450],{"text":258,"type":29},{"type":25,"children":452},[453],{"text":454,"type":29,"marks":455},"Q：测试时 API 返回内容不稳定，会影响地区归因吗？",[456],{"type":265},{"type":25,"children":458},[459],{"text":460,"type":29},"A：会。应固定模型、输入和采样窗口；无法固定时，将内容波动作为单独限制记录。",{"type":25,"children":462},[463],{"text":464,"type":29,"marks":465},"Q：同一地区的两个出口结果不同，能直接认定是 IP 信誉吗？",[466],{"type":265},{"type":25,"children":468},[469],{"text":470,"type":29},"A：不能，先排除网络路径、账号状态和上游时间差，再把结论标为待验证。",{"type":25,"children":472},[473],{"text":474,"type":29,"marks":475},"Q：地区策略由服务方临时调整时，旧测试结论还有效吗？",[476],{"type":265},{"type":25,"children":478},[479],{"text":480,"type":29},"A：只对当时的账号、地区和时间窗口有效，策略变化后应重新验证。",{"source":6,"id":482,"documentId":483,"translationKey":483,"locale":9,"slug":484,"path":485,"_path":485,"title":486,"description":487,"excerpt":487,"image":488,"publishedAt":489,"updatedAt":490,"author":17,"tags":491,"featured":19,"sortOrder":20,"readingTime":32,"bodyType":22,"bodyBlocks":492,"bodyHtml":290},3896,"a6t066253yf747tqsxn0ts4x","http-client-proxy-retry-duplicate-submit-test","\u002Fblog\u002Fhttp-client-proxy-retry-duplicate-submit-test","HTTP 客户端升级后，如何检查代理重试是否导致重复提交","HTTP 客户端升级后，如何检查重试是否导致重复提交？本文用请求计数区分自动重试、重定向重放和连接中断，并说明幂等验证要点。","https:\u002F\u002Fcms.quanqiudaili.com\u002Fuploads\u002Flarge_HTTP_cover_6e441939e4.webp","2026-11-03T03:00:50.977Z","2026-11-03T03:00:50.965Z",[],[493,497,501,505,519,523,527,531,535,553,557,567,571,575,579,593,597,601,605,609,613,624,627,633,637,643,647,653],{"type":25,"children":494},[495],{"text":496,"type":29},"重复提交往往不是业务代码写错，而是客户端在代理 IP 链路上自动重试了非幂等请求。要验证这一点，得让“请求被执行了几次”变成可观测的数字，不靠肉眼核对结果。下面用一个计数接口做靶子，配合注入失败来暴露重试路径。",{"type":31,"level":32,"children":498},[499],{"text":500,"type":29},"怎么判断请求被重复处理了？",{"type":25,"children":502},[503],{"text":504,"type":29},"业务代码调用一次后，客户端可能发送多次网络请求；这不等于业务副作用也执行多次。对照三类记录：客户端发送尝试、服务端接收次数、同一业务键对应的实际副作用次数。再检查幂等键是否一致。只看最终结果不够，因为重复写入可能互相覆盖而不显错。常见重放入口如下：",{"type":41,"format":42,"children":506},[507,511,515],{"type":45,"children":508},[509],{"text":510,"type":29},"重试机制：状态码重试 ｜ 触发条件：503、502、连接超时 ｜ 注入方式：让服务端对部分请求返回 503",{"type":45,"children":512},[513],{"text":514,"type":29},"重试机制：重定向重放 ｜ 触发条件：307、308 通常要求保留方法与请求体 ｜ 注入方式：测试网关让 A 重定向到 B，仅跳转一次；循环作为单独负例并限制跳数",{"type":45,"children":516},[517],{"text":518,"type":29},"重试机制：连接重置重试 ｜ 触发条件：客户端认为请求未发出 ｜ 注入方式：代理侧主动断开连接",{"type":31,"level":32,"children":520},[521],{"text":522,"type":29},"怎么搭建一个可观察请求次数的测试接口？",{"type":25,"children":524},[525],{"text":526,"type":29},"测试接口按业务键统计接收次数和副作用次数，并返回请求序号。日志只保留脱敏关联键、必要状态和计数，过滤认证头、Cookie、URL 凭据与业务正文。测试请求应经过被测客户端和代理路径，以便对照客户端发送、服务端接收及业务处理记录。",{"type":31,"level":32,"children":528},[529],{"text":530,"type":29},"客户端会在什么情况下自动重试？",{"type":25,"children":532},[533],{"text":534,"type":29},"客户端的重试策略由具体库、版本、状态码和请求配置决定，不能只按 HTTP 方法推断。下表列的是需要核验的风险：",{"type":41,"format":42,"children":536},[537,541,545,549],{"type":45,"children":538},[539],{"text":540,"type":29},"方法：GET \u002F HEAD ｜ 方法语义：幂等 ｜ 待核验的风险：通常可安全重试，仍需核对客户端策略与服务端实现",{"type":45,"children":542},[543],{"text":544,"type":29},"方法：PUT \u002F DELETE ｜ 方法语义：幂等 ｜ 待核验的风险：客户端可能重试，需确认服务端确实做过幂等实现",{"type":45,"children":546},[547],{"text":548,"type":29},"方法：POST ｜ 方法语义：非幂等 ｜ 待核验的风险：重试即可能重复创建，需核对客户端策略、幂等键与服务端处理",{"type":45,"children":550},[551],{"text":552,"type":29},"方法：PATCH ｜ 方法语义：非幂等 ｜ 待核验的风险：部分客户端仍会重试，需按具体版本核对",{"type":25,"children":554},[555],{"text":556,"type":29},"升级后要特别确认：新版本是否把 POST 也纳入了可重试范围。这正是重复提交最常见的来源。",{"type":25,"children":558},[559,561,566],{"text":560,"type":29},"需要继续核对投递、签名与重试行为，可参考",{"text":562,"type":29,"marks":563},"SaaS Webhook 地区测试怎么做？到达、签名与重试",[564],{"href":565,"type":186},"https:\u002F\u002Fwww.quanqiudaili.com\u002Fblog\u002Fsaas-webhook-delivery-retry-region-testing",{"text":188,"type":29},{"type":31,"level":32,"children":568},[569],{"text":570,"type":29},"307 和 308 为什么可能重复发送请求？",{"type":25,"children":572},[573],{"text":574,"type":29},"客户端若自动跟随 307\u002F308，通常会尝试保留方法和请求体重新发送，但请求体是否可重放、原请求是否已被处理、服务端是否有副作用，都取决于客户端实现与应用设计。",{"type":25,"children":576},[577],{"text":578,"type":29},"测试时检查客户端是否自动跟随、请求体能否重放，以及 A、B 两端分别收到几次请求：",{"type":41,"format":42,"children":580},[581,585,589],{"type":45,"children":582},[583],{"text":584,"type":29},"是否携带同一个幂等键；",{"type":45,"children":586},[587],{"text":588,"type":29},"是否重复执行了创建逻辑；",{"type":45,"children":590},[591],{"text":592,"type":29},"是否存在重定向循环。",{"type":25,"children":594},[595],{"text":596,"type":29},"仅在隔离的测试环境中，可将 `Location` 指向计数接口，观察客户端是否再次发送请求。请求次数增加说明发生了重放；还需检查服务端是否重复执行了业务操作。若方法或请求体发生变化，应记录具体客户端行为，并对照其版本文档。",{"type":31,"level":32,"children":598},[599],{"text":600,"type":29},"代理连接中断时，写请求会不会被重新发送？",{"type":25,"children":602},[603],{"text":604,"type":29},"断开位置决定服务端是否处理过请求。可在受控环境中分别模拟发送前失败、服务端接收后失败和业务提交后丢弃响应，再对照客户端日志、接收次数与副作用记录。连接重置本身无法说明请求是否已执行。",{"type":31,"level":32,"children":606},[607],{"text":608,"type":29},"怎么模拟失败并确认修复有效？",{"type":25,"children":610},[611],{"text":612,"type":29},"在隔离环境中逐项注入故障：发送前断开、业务提交后丢弃响应、返回 503、A 到 B 的一次 307，以及受控超时。重定向循环另作负例并限制跳数。每轮只改一个条件，记录客户端发送、服务端接收和业务副作用次数。修复后重跑相同用例；只有业务记录没有重复副作用且各层计数符合预期，才算通过。",{"type":25,"children":614},[615,617,622],{"text":616,"type":29},"307\u002F308 的 HTTP 语义见 ",{"text":618,"type":29,"marks":619},"RFC 9110",[620],{"href":621,"type":186},"https:\u002F\u002Fwww.rfc-editor.org\u002Frfc\u002Frfc9110.html",{"text":623,"type":29},"；客户端是否自动跟随及请求体能否重放，应按具体版本验证。",{"type":31,"level":32,"children":625},[626],{"text":258,"type":29},{"type":25,"children":628},[629],{"text":630,"type":29,"marks":631},"Q：幂等键能避免所有重复写入吗？",[632],{"type":265},{"type":25,"children":634},[635],{"text":636,"type":29},"A：不能，需确认服务端确实支持幂等键，并验证键的作用范围和保留时间。",{"type":25,"children":638},[639],{"text":640,"type":29,"marks":641},"Q：读请求和写请求可以使用相同重试策略吗？",[642],{"type":265},{"type":25,"children":644},[645],{"text":646,"type":29},"A：不应默认相同；写请求需评估服务端处理状态未知时的重复执行风险。",{"type":25,"children":648},[649],{"text":650,"type":29,"marks":651},"Q：客户端没有收到响应，能否判断服务端未处理请求？",[652],{"type":265},{"type":25,"children":654},[655],{"text":656,"type":29},"A：不能。连接中断时处理状态可能未知，应通过服务端记录或业务状态核对。",{"source":6,"id":658,"documentId":659,"translationKey":659,"locale":9,"slug":660,"path":661,"_path":661,"title":662,"description":663,"excerpt":663,"image":664,"publishedAt":665,"updatedAt":666,"author":17,"tags":667,"featured":19,"sortOrder":20,"readingTime":668,"bodyType":22,"bodyBlocks":669,"bodyHtml":290},3895,"tf37dm2ee9mh0u8xbco8p5ch","go-transport-proxy-connection-regression","\u002Fblog\u002Fgo-transport-proxy-connection-regression","Go 版本或 Transport 配置变更后，如何重新检查代理连接","Go 版本或 Transport 配置变更后，如何检查代理连接？本文核对代理配置来源，并对照连接复用、TLS、HTTP\u002F2 和分阶段耗时。","https:\u002F\u002Fcms.quanqiudaili.com\u002Fuploads\u002Flarge_Go_Transport_cover_4e51fe43de.webp","2026-11-03T03:00:34.422Z","2026-11-03T03:00:34.401Z",[],4,[670,674,678,682,696,700,704,708,712,716,720,724,728,732,736,740,750,754,758,772,776,780,784,798,802,806,810,814,818,840,844,851,854,860,864,870,874,880],{"type":25,"children":671},[672],{"text":673,"type":29},"Go 的代理 IP 行为由版本、环境变量和 `Transport` 配置共同决定，任何一项变化都可能改变实际走向。回归的关键是把“代理从哪来”和“请求走到哪一步”都变成可观测的。下面用标准库的 `httptrace` 与会话复用指标做示范，测试在自有服务与测试出口上进行。",{"type":31,"level":32,"children":675},[676],{"text":677,"type":29},"升级后先确认 Go 版本和哪些配置变了",{"type":25,"children":679},[680],{"text":681,"type":29},"先记录 Go 版本、构建选项和代理环境配置，作为升级前后对照基线：",{"type":41,"format":42,"children":683},[684,688,692],{"type":45,"children":685},[686],{"text":687,"type":29},"Go 版本：`go version`，大版本升级可能改变默认 TLS 与 HTTP\u002F2 行为；",{"type":45,"children":689},[690],{"text":691,"type":29},"GOFLAGS 与构建标签：是否启用或关闭了某些默认行为；",{"type":45,"children":693},[694],{"text":695,"type":29},"环境变量：`HTTP_PROXY`、`HTTPS_PROXY`、`NO_PROXY` 是否被设置，以及大小写写法。",{"type":25,"children":697},[698],{"text":699,"type":29},"`HTTP_PROXY` 与 `http_proxy` 的处理及 `NO_PROXY` 匹配规则应按 Go 版本核实。回归前记录变量是否设置、脱敏后的主机\u002F端口与绕过规则，再和升级前记录对比。不要输出含 URL userinfo、口令或完整凭据的代理环境变量。",{"type":31,"level":32,"children":701},[702],{"text":703,"type":29},"Go 请求最终使用了哪种代理配置？",{"type":25,"children":705},[706],{"text":707,"type":29},"最终用哪套配置，以当前请求实际使用的 `Transport` 和绕过规则为准。除了 `Proxy`，还要检查自定义 `DialContext`、`NO_PROXY`、重定向和连接池；环境变量是否被读取还取决于读取时机，不能只看代码或环境变量就下判断。",{"type":25,"children":709},[710],{"text":711,"type":29},"```go\ntr := &http.Transport{\nProxy: http.ProxyFromEnvironment, \u002F\u002F 读环境变量\n\u002F\u002F Proxy: http.ProxyURL(proxyURL), \u002F\u002F 显式指定\nTLSHandshakeTimeout: 5 * time.Second,\n}\nclient := &http.Client{Transport: tr, Timeout: 30 * time.Second}\nreq, _ := http.NewRequest(\"GET\", \"https:\u002F\u002Fapi.example.com\u002Fv1\u002Fmodels\", nil)\nreq.Header.Set(\"Authorization\", \"Bearer \"+os.Getenv(\"API_KEY\"))\nresp, err := client.Do(req)\n```",{"type":25,"children":713},[714],{"text":715,"type":29},"若 `Transport.Proxy` 显式设置了代理函数或地址，请求将按该配置处理，不会再由另一套环境变量配置替代。使用标准库 `ProxyFromEnvironment` 时，代理环境配置存在进程级缓存行为；按目标 Go 版本核对实现。修改环境变量后，应在设置好环境的新进程中测试，只新建 Transport 不保证刷新缓存。需要运行时动态选择代理时，用明确管理的 `Proxy` 函数或 `ProxyURL`，并单独管理连接池。",{"type":25,"children":717},[718],{"text":719,"type":29},"在隔离测试环境中，可将代理地址指向不可用端口作为负向测试。请求仍成功只说明该请求没有依赖这个代理配置；还应排查 `NO_PROXY`、其他代理设置、连接复用等因素，并核对最终出口。",{"type":25,"children":721},[722],{"text":723,"type":29},"`NO_PROXY` 命中时请求会绕过代理；应把匹配结果与实际出口一起核对。",{"type":31,"level":32,"children":725},[726],{"text":727,"type":29},"怎么用 `httptrace` 定位连接耗时？",{"type":25,"children":729},[730],{"text":731,"type":29},"`httptrace` 提供的是阶段事件，不是现成的耗时报表；需要在事件回调里记时间戳、算差值，再和总耗时对照。",{"type":25,"children":733},[734],{"text":735,"type":29},"```go\nstart := time.Now()\nvar dnsStart, connStart, tlsStart time.Time\ntrace := &httptrace.ClientTrace{\nDNSStart:          func(httptrace.DNSStartInfo) { dnsStart = time.Now() },\nDNSDone:           func(httptrace.DNSDoneInfo) { log.Printf(\"dns %v\", time.Since(dnsStart)) },\nConnectStart:      func(network, addr string) { connStart = time.Now(); log.Printf(\"connect start %s %s\", network, addr) },\nConnectDone:       func(network, addr string, err error) { log.Printf(\"connect done %s %v %v\", addr, time.Since(connStart), err) },\nTLSHandshakeStart: func() { tlsStart = time.Now() },\nTLSHandshakeDone: func(cs tls.ConnectionState, err error) {\nlog.Printf(\"tls %v proto=%s\", time.Since(tlsStart), cs.NegotiatedProtocol)\n},\nGotFirstResponseByte: func() { log.Printf(\"ttfb %v\", time.Since(start)) },\n}\nreq = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))\n```",{"type":25,"children":737},[738],{"text":739,"type":29},"开始事件与完成事件要成对记录，才能计算 DNS、拨号、TLS 等阶段时长；只注册起点不会得到 duration。示例中的单一时间变量只适用于串行、单次尝试；Happy Eyeballs 等情况下可能并发或多次触发回调，应按连接尝试关联时间戳，并用互斥锁或并发安全结构保护。若连接复用，可能没有新的拨号事件，缺事件不等于零耗时。代理下 `ConnectStart` 的目标通常是代理地址；经 HTTP 代理时 DNS 也可能由代理完成。",{"type":25,"children":741},[742,744,749],{"text":743,"type":29},"移动应用场景的 DNS、连接和 TLS 分阶段定位方法，可参考",{"text":745,"type":29,"marks":746},"移动 App 网络兼容测试：五个失败阶段定位法",[747],{"href":748,"type":186},"https:\u002F\u002Fwww.quanqiudaili.com\u002Fblog\u002Fmobile-app-network-egress-compatibility-testing",{"text":188,"type":29},{"type":31,"level":32,"children":751},[752],{"text":753,"type":29},"怎么确认连接复用和超时设置仍然生效？",{"type":25,"children":755},[756],{"text":757,"type":29},"检查连接池配置与 `GotConn` 事件，比较同一负载下的复用结果：",{"type":41,"format":42,"children":759},[760,764,768],{"type":45,"children":761},[762],{"text":763,"type":29},"`DisableKeepAlives: true` 会让每个请求重新建连；",{"type":45,"children":765},[766],{"text":767,"type":29},"`TLSHandshakeTimeout` 过短会在跨境链路上频繁失败；",{"type":45,"children":769},[770],{"text":771,"type":29},"`MaxIdleConnsPerHost` 过低会导致高并发时连接被丢弃重建。",{"type":25,"children":773},[774],{"text":775,"type":29},"观测方式：看 `httptrace.GotConn` 回调里 `info.Reused` 的取值，统计连续请求中的复用比例。复用比例受请求模式、连接池和服务端行为影响，不设统一阈值；将升级前后相同负载下的结果对照，异常时再检查配置和默认值。",{"type":31,"level":32,"children":777},[778],{"text":779,"type":29},"升级后 HTTP\u002F2 或 TLS 协商有什么变化？",{"type":25,"children":781},[782],{"text":783,"type":29},"Go 版本升级可能改变 HTTP\u002F2 启用条件和 TLS 默认值，判断时以 Go 客户端自己的结果为准。",{"type":41,"format":42,"children":785},[786,790,794],{"type":45,"children":787},[788],{"text":789,"type":29},"自定义 `TLSClientConfig` 可能关闭 HTTP\u002F2；",{"type":45,"children":791},[792],{"text":793,"type":29},"`ForceAttemptHTTP2` 的设置会影响协商结果；",{"type":45,"children":795},[796],{"text":797,"type":29},"最低 TLS 版本提升后，旧代理或中间设备可能握手失败。",{"type":25,"children":799},[800],{"text":801,"type":29},"以 Go 的 `resp.Proto`、`resp.TLS.NegotiatedProtocol`（TLS 响应时）及客户端日志作为 Go 实际协商结果。curl 只能作显式相同代理、目标和路径下的独立对照，不能代表 Go 客户端结果：",{"type":25,"children":803},[804],{"text":805,"type":29},"```bash\ncurl -sI -o \u002Fdev\u002Fnull -w '%{http_version}\\n' https:\u002F\u002Fapi.example.com\u002F\n```",{"type":25,"children":807},[808],{"text":809,"type":29},"该命令只显示 curl 自己的协商结果；Go 的结果以 `resp.Proto` 与 TLS 状态为准。两者不一致时，先确认代理、目标和请求路径相同，再检查 Go 版本、`tls.Config` 与代理隧道能力。",{"type":31,"level":32,"children":811},[812],{"text":813,"type":29},"怎么判断代理连接回归通过？",{"type":25,"children":815},[816],{"text":817,"type":29},"可按下表对照代理来源、分阶段耗时、连接复用、协议协商及超时重试。",{"type":41,"format":42,"children":819},[820,824,828,832,836],{"type":45,"children":821},[822],{"text":823,"type":29},"检查项：代理来源 ｜ 观测点：检查 `Transport.Proxy`、绕过规则及实际出口 ｜ 正常表现：与预期代理配置和出口一致",{"type":45,"children":825},[826],{"text":827,"type":29},"检查项：分阶段耗时 ｜ 观测点：`httptrace` 成对事件算出的各段时长 ｜ 正常表现：各段与升级前同一量级",{"type":45,"children":829},[830],{"text":831,"type":29},"检查项：连接复用 ｜ 观测点：`GotConn` 的 `Reused` ｜ 正常表现：与升级前相同负载下的基线对照",{"type":45,"children":833},[834],{"text":835,"type":29},"检查项：Go 协商协议 ｜ 观测点：`resp.Proto` 与 TLS 状态 ｜ 正常表现：按目标服务、代理路径和升级前基线核对",{"type":45,"children":837},[838],{"text":839,"type":29},"检查项：超时与重试 ｜ 观测点：三类超时的触发日志 ｜ 正常表现：各按预期触发，次数不变",{"type":25,"children":841},[842],{"text":843,"type":29},"如果实际出口与配置不符，先检查 `Transport.Proxy` 和绕过规则；若某阶段耗时变化，检查对应的连接与超时配置；HTTP\u002F2 协商结果变化时，再核对 Go 版本、TLS 配置和代理支持情况。",{"type":25,"children":845},[846],{"text":847,"type":29,"marks":848},"Go net\u002Fhttp 官方文档",[849],{"href":850,"type":186},"https:\u002F\u002Fpkg.go.dev\u002Fnet\u002Fhttp",{"type":31,"level":32,"children":852},[853],{"text":258,"type":29},{"type":25,"children":855},[856],{"text":857,"type":29,"marks":858},"Q：环境变量代理设置会自动覆盖自定义 Transport 吗？",[859],{"type":265},{"type":25,"children":861},[862],{"text":863,"type":29},"A：取决于 `Transport.Proxy` 是否显式设置及 Go 版本行为，应以实际配置和版本文档为准。",{"type":25,"children":865},[866],{"text":867,"type":29,"marks":868},"Q：测试关闭连接复用会代表线上表现吗？",[869],{"type":265},{"type":25,"children":871},[872],{"text":873,"type":29},"A：不会。它适合隔离连接问题，结果应与默认复用配置分开记录。",{"type":25,"children":875},[876],{"text":877,"type":29,"marks":878},"Q：只在一个 Go 版本通过是否足够？",[879],{"type":265},{"type":25,"children":881},[882],{"text":883,"type":29},"A：若生产使用多个版本，应覆盖实际部署版本及升级目标版本。",[885],{"source":6,"id":7,"documentId":8,"translationKey":8,"locale":9,"slug":10,"path":11,"_path":11,"title":12,"description":13,"excerpt":13,"image":14,"publishedAt":15,"updatedAt":16,"author":17,"tags":886,"featured":19,"sortOrder":20,"readingTime":21,"bodyType":22,"bodyBlocks":887,"bodyHtml":290},[],[888,891,894,897,911,914,917,920,923,926,937,940,954,957,960,971,974,977,980,994,997,1000,1007,1010,1013,1021,1024,1027,1030,1050,1057,1060,1065,1068,1073,1076,1081],{"type":25,"children":889},[890],{"text":28,"type":29},{"type":31,"level":32,"children":892},[893],{"text":35,"type":29},{"type":25,"children":895},[896],{"text":39,"type":29},{"type":41,"format":42,"children":898},[899,902,905,908],{"type":45,"children":900},[901],{"text":48,"type":29},{"type":45,"children":903},[904],{"text":52,"type":29},{"type":45,"children":906},[907],{"text":56,"type":29},{"type":45,"children":909},[910],{"text":60,"type":29},{"type":25,"children":912},[913],{"text":64,"type":29},{"type":31,"level":32,"children":915},[916],{"text":68,"type":29},{"type":25,"children":918},[919],{"text":72,"type":29},{"type":25,"children":921},[922],{"text":76,"type":29},{"type":25,"children":924},[925],{"text":80,"type":29},{"type":41,"format":42,"children":927},[928,931,934],{"type":45,"children":929},[930],{"text":86,"type":29},{"type":45,"children":932},[933],{"text":90,"type":29},{"type":45,"children":935},[936],{"text":94,"type":29},{"type":25,"children":938},[939],{"text":98,"type":29},{"type":41,"format":42,"children":941},[942,945,948,951],{"type":45,"children":943},[944],{"text":104,"type":29},{"type":45,"children":946},[947],{"text":108,"type":29},{"type":45,"children":949},[950],{"text":112,"type":29},{"type":45,"children":952},[953],{"text":116,"type":29},{"type":31,"level":32,"children":955},[956],{"text":120,"type":29},{"type":25,"children":958},[959],{"text":124,"type":29},{"type":41,"format":42,"children":961},[962,965,968],{"type":45,"children":963},[964],{"text":130,"type":29},{"type":45,"children":966},[967],{"text":134,"type":29},{"type":45,"children":969},[970],{"text":138,"type":29},{"type":25,"children":972},[973],{"text":142,"type":29},{"type":31,"level":32,"children":975},[976],{"text":146,"type":29},{"type":25,"children":978},[979],{"text":150,"type":29},{"type":41,"format":42,"children":981},[982,985,988,991],{"type":45,"children":983},[984],{"text":156,"type":29},{"type":45,"children":986},[987],{"text":160,"type":29},{"type":45,"children":989},[990],{"text":164,"type":29},{"type":45,"children":992},[993],{"text":168,"type":29},{"type":25,"children":995},[996],{"text":172,"type":29},{"type":25,"children":998},[999],{"text":176,"type":29},{"type":25,"children":1001},[1002,1003,1006],{"text":180,"type":29},{"text":182,"type":29,"marks":1004},[1005],{"href":185,"type":186},{"text":188,"type":29},{"type":31,"level":32,"children":1008},[1009],{"text":192,"type":29},{"type":25,"children":1011},[1012],{"text":196,"type":29},{"type":41,"format":42,"children":1014},[1015,1018],{"type":45,"children":1016},[1017],{"text":202,"type":29},{"type":45,"children":1019},[1020],{"text":206,"type":29},{"type":25,"children":1022},[1023],{"text":210,"type":29},{"type":31,"level":32,"children":1025},[1026],{"text":214,"type":29},{"type":25,"children":1028},[1029],{"text":218,"type":29},{"type":41,"format":42,"children":1031},[1032,1035,1038,1041,1044,1047],{"type":45,"children":1033},[1034],{"text":224,"type":29},{"type":45,"children":1036},[1037],{"text":228,"type":29},{"type":45,"children":1039},[1040],{"text":232,"type":29},{"type":45,"children":1042},[1043],{"text":236,"type":29},{"type":45,"children":1045},[1046],{"text":240,"type":29},{"type":45,"children":1048},[1049],{"text":244,"type":29},{"type":25,"children":1051},[1052,1053,1056],{"text":248,"type":29},{"text":250,"type":29,"marks":1054},[1055],{"href":253,"type":186},{"text":188,"type":29},{"type":31,"level":32,"children":1058},[1059],{"text":258,"type":29},{"type":25,"children":1061},[1062],{"text":262,"type":29,"marks":1063},[1064],{"type":265},{"type":25,"children":1066},[1067],{"text":269,"type":29},{"type":25,"children":1069},[1070],{"text":273,"type":29,"marks":1071},[1072],{"type":265},{"type":25,"children":1074},[1075],{"text":279,"type":29},{"type":25,"children":1077},[1078],{"text":283,"type":29,"marks":1079},[1080],{"type":265},{"type":25,"children":1082},[1083],{"text":289,"type":29},null,[],[]]