尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

HAR文件从导出到应用:Chrome Network高效调试指南

HAR文件从导出到应用:Chrome Network高效调试指南 做前端和接口联调的人应该都有过这种经历后端说“我这边没问题你抓个包给我看看”然后你打开Chrome开发人员工具里的Network面板右键一下把请求复制成cURL或者直接截图发过去。截图往往截不全cURL丢三落四直到我发现HAR文件这种格式才算真正找到了一个跨端、跨人的“请求黑匣子”。HARHTTP Archive Format本质是JSON它把浏览器每一次请求的URL、请求头、请求体、响应头、响应体、耗时、Cookie等全部记录在一个文件里不管是自己排查还是发给同事都非常够用。这篇文章就围绕Chrome开发人员工具Network面板里的HAR文件聊聊怎么导出、怎么读、怎么用以及那些不那么明显但很重要的坑。1. HAR文件是什么为什么值得花时间了解1.1 HAR文件的历史与定位HAR全称HTTP Archive Format最初由W3C Web Performance工作组推动制定目的是把浏览器发出的HTTP请求完整归档下来方便性能分析和问题复现。它本质是一个JSON对象后缀名通常为.har但用任何文本编辑器都能打开。你可以把它理解成“给网络请求拍了一张高清快照”页面加载过程中所有资源请求、接口调用、静态文件加载、耗时数据全部装进一个文件里。这个格式的意义在于“通用”。Chrome能导出Firefox能导出Safari能导出Charles、Fiddler这些抓包工具也支持。只要对方手里有一个HAR文件他不需要和你同环境、同网络、同设备就能把问题还原个八九不离十。我在实际中遇到好多次两边环境不一样接口行为对不上最后靠一份HAR把“到底发了什么请求、返回了什么内容”钉死谁都不用再猜。1.2 为什么用HAR而不直接复制cURL有人会问Network面板里右键不是有“Copy as cURL”吗为什么还要用HAR确实cURL命令能把单个请求复现出来特别适合快速验证接口。但只复制单个请求有几个明显短板覆盖不完整。一个页面可能涉及几十个请求你不可能一条条去复制。上下文丢失。Cookie、referer、用户代理、跨域跳转等信息容易漏掉复制出来的cURL很难完整还原。没有时间维度。你看不出请求的先后顺序、阻塞时间、DNS耗时也无法分析性能瓶颈。不会保存响应内容。你只能拿到请求拿不到服务器返回的数据排查响应问题时还要重新发一遍。HAR则把整个会话的请求记录连锅端连每个请求的耗时、依赖关系、响应体都带上了。它更像一份完整的“案发现场记录”而不是一个“孤立的命令”。1.3 什么场景下HAR最有用HAR不是个高深工具但用对场景能省掉大量沟通成本。我常用的场景基本是三类接口联调。前端说“我发了请求为什么报500”后端说“我这没看到日志”把HAR发过去请求体和请求头都清清楚楚问题定位快很多。性能分析。页面加载慢光看感觉没用导一份HAR看每个资源的耗时和加载顺序瓶颈在域名解析、慢接口还是大图片一目了然。线上问题复现。用户反馈页面白屏你没法跑用户环境让用户按个快捷键导出一份HAR传给你大部分时候能直接看出是哪个接口挂了或者哪个资源没加载。所以这篇文章适合前端、后端、测试、运维以及所有需要跟网络请求打交道的人。哪怕你不写代码只要会用浏览器学会HAR也能帮你把问题描述清楚。2. 从Chrome开发人员工具Network面板导出HAR文件2.1 打开Network面板并正确录制请求我见过不少人在导出HAR时发现“请求怎么不全”其实多数是第一步就没做好。打开Chrome按F12或者CtrlShiftI进入开发人员工具找到Network面板然后注意几个关键选项。第一个是Preserve log。默认情况下页面发生跳转或刷新Network面板里的请求记录会被清空。如果你要抓的是一个完整访问流程比如从进入页面到点击按钮提交表单那必须勾选Preserve log否则中间一跳转你就什么都看不见了。第二个是Disable cache。如果你在排查线上加载问题建议勾上。浏览器命中缓存后HAR里记录的请求可能不会真正发送响应直接从本地读取time字段也会变成接近0。这会让分析结果严重失真。用无痕窗口也可以但无痕窗口本身也会缓存为了避开缓存问题我通常直接勾选Disable cache再录制。第三个是Filter输入框。录制前不用刻意过滤但录制完要分析某类请求时可以输入api、static、js、css等关键词。注意这里支持常见的通配符和正则匹配例如/api\//可以匹配含api路径的请求用熟了比手动翻列表快得多。录制的动作也很重要清空列表点左上角清除按钮后再刷新页面或者执行操作。如果你是模拟用户操作比如登录、下单、上传最好把动作放慢一些确保所有请求都已经发出的状态然后再导出。2.2 导出HAR的三种常见方式等请求记录完成接下来就是导出。Chrome的Network面板提供了几种方式我按习惯的使用频率介绍一下。第一种是右键点击请求列表区域在列表任意一条记录上点右键菜单里会出现“Save all as HAR with content”。注意如果你只是右键单条请求菜单里通常只有“Save as HAR with content”那个只会保存你选中的那一条。要保存全部必须右键在空白区域或者确保列表里所有请求都被选中然后选择Save all。第二种是点击Network面板左上角的“Export HAR”图标。这个图标长得像一个向下的箭头悬停会显示“Export HAR”。点击之后浏览器会直接把当前录制到的所有请求打包成一个.har文件下载到你默认的下载目录。这个方式最简单不容易误操作。第三种是从DevTools的主菜单里导出。点击右上角三个点的自定义菜单选择More tools再选HAR export或者某些版本里直接在菜单中能找到“Export HAR”。这个方法稍微绕一点但胜在不容易被列表右键的选项干扰。这里要特别强调一下“with content”的含义。如果你选择“Save all as HAR with content”导出的HAR里会包含每个响应体的实际内容比如JSON接口返回的数据、HTML源码、图片的Base64编码。如果取消“with content”文件体积会小很多但HAR里就只剩下请求/响应的元数据没有响应体。排查接口返回内容时必须带content只做性能分析时可以不带。2.3 导入HAR文件进行离线分析导出HAR不只是为了发给别人自己复盘同样有用。Chrome支持直接把HAR文件拖回Network面板。具体操作很简单打开DevTools的Network面板把.har文件从文件管理器拖拽到请求列表区域松开鼠标Chrome会在Network面板中重新展示这份HAR里的所有请求就像你是现场抓到的一样。导入之后你可以像平时一样点击任意请求查看请求头、响应体、耗时、Cookie等。这比打开一个JSON文件硬看要直观得多。更重要的是即使你断网了只要HAR里带了响应内容你依然能查看当时服务器返回的数据。我把这个功能当成“离线快照查看器”用很多线上事故就是靠这一手复盘的。这里有个小技巧如果你在本地把HAR文件关联到一个顺手的工具比如Chrome本身双击文件也能快速打开DevTools并加载。不过这不是标准行为不同系统表现不一致建议还是手动拖拽最稳妥。2.4 录制阶段的几个关键设置导出HAR看起来容易但录制的质量直接决定HAR的可用性。根据我的经验有几个设置要养成习惯。勾选Preserve log防止跳转清空记录。勾选Disable cache保证请求真实发出去。打开Network面板后先点击左上角的停止/开始录制按钮确保处于录制状态。有时候面板没激活请求列表可能不更新错觉以为页面没发请求。如果页面里有跨域iframe、WebSocket、Service Worker等流量普通Network列表不会完整显示。至少要把筛选器切到All不要只看XHR或Fetch标签。录制结束后给出一个清楚的文件名。我习惯用项目名-功能-日期.har例如mall-order-20250120.har这样后续归档不会乱。这些步骤做完导出的HAR才具备完整的可分析价值。3. HAR文件内部结构完全拆解3.1 顶层字段log、version、creator、pagesHAR既然是JSON结构就是一棵树。所有内容都在根对象log下面。打开一份HAR你会看到类似这样的结构{ log: { version: 1.2, creator: { name: Chrome, version: 120.0.0.0 }, pages: [ { startedDateTime: 2025-01-20T10:00:00.000Z, id: page_1, title: example.com, pageTimings: { onContentLoad: 320.5, onLoad: 580.2 } } ], entries: [] } }version表示HAR规范的版本号常见的是1.1和1.2。creator保存生成这个文件的工具名称和版本分析时如果发现字段有差异可以先看看creator是谁。pages是可选字段Chrome导出的HAR里通常会有记录页面级的开始时间、id、标题以及两个关键时间点onContentLoad和onLoad分别对应DOMContentLoaded和window.onLoad事件发生的时间。entries是这个文件的核心一个数组里面每一项代表一个HTTP请求。3.2 entries数组每个请求的真实记录entries的每一项都是独立的对象包含一个完整HTTP事务的所有信息。核心字段如下字段含义startedDateTime请求开始时间ISO格式含时区time整个请求的总耗时单位毫秒request请求详情response响应详情cache缓存信息timings各阶段耗时明细serverIPAddress服务器IPconnection连接标识用于判断连接复用_resourceTypeChrome扩展字段标记资源类型其中time通常等于timings里各阶段耗时之和。注意它不一定等于你感知到的“从发请求到收到响应”的时间因为浏览器计算的是从创建请求到完成响应的总时间。遇到某个请求的time为0通常代表这个请求根本没发比如被浏览器缓存拦截了。3.3 request对象请求是怎么发出去的每个entry里的request对象描述客户端实际发出的请求。基本内容包括request: { method: POST, url: https://api.example.com/login, httpVersion: HTTP/2, headers: [ {name: Content-Type, value: application/json}, {name: Authorization, value: Bearer ...} ], queryString: [ {name: from, value: home} ], cookies: [ {name: sessionid, value: abc123} ], headersSize: 230, bodySize: 29, postData: { mimeType: application/json, text: {\username\:\admin\} } }这里要理解headers和cookies的区别。cookies是浏览器自动从Cookie store里带出来的请求Cookie而headers里也会出现Cookie头两者会重复。做接口签名或者鉴权分析时不管从哪个字段取都要先确认一致性。queryString是把URL中问号后面的参数解析成键值对列表方便直接看。比如URL是/api/user?id1langzh这里就会有id和lang两项。这个字段在HAR v1.2里是标准字段早期有些工具缺这个需要自行解析。postData是POST请求的核心。如果Content-Type是application/x-www-form-urlencodedtext里通常是keyvaluekey2value2的字符串如果是application/jsontext里就是JSON字符串。如果提交的是文件还可能出现params数组和comment字段。联调时把postData.text原样贴给后端比什么都管用。3.4 response对象服务器返回了什么response对象把服务器返回的信息完整保留下来主要字段如下response: { status: 200, statusText: OK, httpVersion: HTTP/2, headers: [ {name: Content-Type, value: application/json} ], cookies: [], content: { size: 518, mimeType: application/json, compression: 40, text: {\code\:0,\data\:{}} }, redirectURL: , headersSize: 120, bodySize: 478 }status和statusText是HTTP状态码和原因短语比如404和Not Found。content里保存响应内容相关数据其中text字段最为关键。如果你是勾选了“Save all as HAR with content”导出的这里会包含完整的响应文本。对于图片、字体等二进制资源text可能会是Base64编码的字符串同时结构中会出现encoding: base64字段。redirectURL在3xx响应里会显示跳转目标地址分析重定向链路时很有用。headersSize和bodySize分别是响应头字节数和响应体字节数。注意content.size和bodySize的含义不完全一样前者是解码后的内容大小后者是实际传输的字节大小如果启用了gzip压缩两者会有明显差异。3.5 timings与页面加载时间线做性能分析的人最应该看的是timings对象。它记录了请求各阶段的耗时字段含义如下字段说明blocked请求从发起到真正进入队列前的阻塞时间包括等待空闲连接等dnsDNS解析耗时connectTCP建连耗时包含SSL握手sslSSL/TLS握手耗时Chrome会把这段时间独立标出send发送请求体耗时wait等待服务器响应首个字节的时间TTFBreceive接收响应体耗时如果某个阶段的值是 -1不代表出错而是代表这个阶段没有被记录下来或者请求复用了已有连接不需要这个阶段。例如第二次访问同一站点时DNS耗时和connect耗时都可能是-1因为连接早已建立。页面加载时间线还要结合pages里的pageTimings来看。onContentLoad对应DOM解析完成的时间onLoad对应所有资源加载完成的时间。如果你想确认“页面上为什么有个接口特别慢”找到那个entry的wait值基本就等于看到服务器的处理时间了。3.6 cache与扩展字段cache对象一般长这样cache: { beforeRequest: null, afterRequest: null }它记录请求发出前和响应返回后浏览器缓存的状态。大多数情况下这两个字段都是null表示没有额外缓存信息。但如果你分析静态资源加载可能会看到expires、lastModified、etag等缓存元数据这时候不要忽略它们。另外Chrome在导出HAR时还会加上一些下划线开头的扩展字段比如_resourceType、_priority、_initiator。_resourceType表示资源类型例如script、xhr、stylesheet等脚本过滤时非常方便。_initiator表示是谁发起了这个请求比如某个脚本文件。这些不是HAR标准字段但分析时可以用。4. 如何高效分析和使用HAR文件4.1 用Chrome开发人员工具直接复盘HAR最简单的分析方式就是前面说的把HAR拖回Network面板。导入后请求列表会恢复成现场状态可以点击任意一条请求查看细节甚至切换到底部的Timing标签查看该请求各阶段耗时。我复盘性能问题时的固定动作是导入HAR先看列表里的Time列按耗时从高到低排个序很快就能找出最慢的那几个请求。然后逐个点开在Timing标签里看是卡在wait还是卡在receive。如果多数请求都卡在wait问题大概率在后端接口响应太慢如果receive很长则可能是下载了大体积资源。需要注意的是Chrome的Network面板导入HAR后不能直接“重新发送”某个请求。因为它只是一个记录查看器不是接口调试工具。如果要从HAR里挑出某个请求重新执行可以把关键字段复制出来用Postman、Apifox或者直接curl。4.2 用HAR Viewer做可视化分析除了Chrome自带的Network面板HAR文件还可以导入到一些可视化工具里。比较常用的是Google的HAR Archive Viewer拖拽文件就能看到请求列表和瀑布图另外像HAR Analyzer这类开源工具也支持把HAR渲染成前端性能报告。在线工具的优势是操作简单分享方便缺点是上传敏感数据有泄露风险而且巨型HAR文件经常会把浏览器卡死。所以我一般只拿在线工具处理体积小于5MB的HAR且确认文件里不包含敏感Cookie或Token。更稳妥的做法是本地分析。Charles和Fiddler都支持导入HAR导入后可以查看请求/响应详情。Postman也支持导入HAR它会自动把HAR里的每个请求转换成集合中的一条记录这样就能直接对单个接口做二次调试。如果你本身就在用Postman遇到HAR里的请求想快速验证导入之后点Send就行。4.3 写个脚本自己解析HAR提取关键信息当HAR文件数量多、或者需要批量分析时用工具点来点去效率太低。我习惯直接写脚本解析。因为HAR就是JSONPython、Node.js都可以很快处理。下面给一个通用的Python示例用来遍历所有请求输出状态码、耗时、请求方法、URL路径。import json from urllib.parse import urlparse with open(demo.har, r, encodingutf-8) as f: har json.load(f) for entry in har[log][entries]: req entry[request] resp entry[response] status resp[status] time_ms entry[time] url req[url] path urlparse(url).path print(f{status} {time_ms:8.2f}ms {req[method]:6s} {path})这段代码足以应付大多数情况。如果你想找最慢的接口可以加一行排序用sorted(entries, keylambda e: e[time], reverseTrue)取前十条。想统计哪个域名请求最多可以用Counter(urlparse(e[request][url]).netloc)。另一个常用需求是检查失败的请求。你只要筛选resp[status] 400的条目然后打印出请求方法和URL就能快速定位到所有报错请求。注意HAR里还可能存在error字段比如连接中断时浏览器会记录错误信息过滤时可一并用上。4.4 多份HAR对比定位差异有些问题不是一次HAR能看出来的需要对比。我在性能优化时常用“改动前后对比”先在优化前导出一份HAR做完改动后再导一份然后用脚本把每个请求的耗时、资源大小、请求顺序拉出来比较。具体操作是把两份HAR分别加载成两个Python对象以URL作为key构建一个字典然后对齐每个请求的耗时和大小。你会发现很多时候问题不在单个请求而在于请求顺序和依赖关系。例如第三方的统计脚本放在首屏关键路径上就算它本身只要50ms也会拖慢整个load事件。多份HAR对比还可以用来做线上和本地环境的差异分析。比如本地环境接口一切正常线上环境偶发超时把两边的HAR拿出来比对请求头、Cookie、域名解析地址经常能发现是线上某个中间层或者代理追加了多余操作。4.5 典型业务场景实战我把最常见的HAR应用场景拆开说场景一前后端接口联调。前端这边提交一个保存操作后端说报错但看不到请求。前端把HAR导出找到对应POST请求直接把response.status、response.content.text截图再把request.postData.text发给后端。后端很快能判断是参数格式问题还是服务端异常。场景二页面性能优化。用户反馈首屏加载要8秒导出一份HAR按域名统计请求数和大小发现图片总大小占60%其中一张背景图就2MB。优化手段也就很清楚了压缩图片、改用CDN、加懒加载。场景三线上环境白屏。用户反馈页面空白让用户导出HAR后先看有没有JS文件返回404或500再看接口返回是否异常再看是否有跨域报错导致资源被拦截。通常问题就在这三块里。这些场景的核心都一样用数据说话而不是靠猜。5. 常见问题与避坑指南5.1 HAR文件太大打开就卡死一份完整包含响应内容的大型页面HAR动辄几十MB甚至上百MB。Chrome导入时还能扛住但某些在线工具和文本编辑器就非常吃力了。这个时候有几种处理思路。第一导出时选择不含content只保留请求/响应元数据文件大小能缩小到原来的十分之一以下。第二如果已经导出大文件可以用脚本剔除content字段再保存。Python处理很简单import json with open(big.har, r, encodingutf-8) as f: har json.load(f) for entry in har[log][entries]: resp entry[response] if content in resp: resp[content].pop(text, None) resp[content].pop(encoding, None) resp[content][comment] text removed to reduce size with open(small.har, w, encodingutf-8) as f: json.dump(har, f)处理完后文件体积会大幅下降适合分享和快速浏览元数据。缺点是不能再离线查看响应体内容。5.2 敏感信息泄露问题这个必须重视HAR是JSON纯文本任何打开它的人都能看到里面的所有内容。我这几年见过太多次因为分享HAR而泄露Token、登录态、Cookie、密码字段的案例。你发给“后端同事”的HAR中间可能经手其他工具、其他人风险远比想象中高。所以我的铁律是导出HAR后先搜索有没有Authorization、Cookie、Set-Cookie、password、token等敏感关键词。再用脚本做一次脱敏把这些关键字段替换成***。如果只是分析性能直接导出不含content的版本减少响应体泄露。如果必须在线上工具里查看优先选择本地工具或者内网部署的分析器不要随手拖到公共网站。5.3 导出HAR后发现请求缺失怎么回事最常见的原因是没勾Preserve log页面刷新时历史请求被清掉。其次是过滤器影响如果当前Network面板的过滤器是XHR那你导出的HAR里只有XHR请求其他图片、CSS、JS都不会出现。导出前一定要确认筛选器是All。还有一种情况是扩展脚本或者Service Worker拦截了请求浏览器Network面板里能看到正常请求但HAR导出时有些请求由于被后台处理没有完整的HTTP事务。你可以检查是否安装了广告拦截、代理切换等扩展必要时先停用再录制。另外WebSocket和Server-Sent Events不会作为普通HTTP请求出现在HAR的entries里。如果你需要分析这两个协议建议使用专门的调试工具别指望一份HAR搞定所有传输层问题。5.4 timings数据和真实观感不一致很多人在分析HAR时会被time字段误导。time是从请求开始到响应完成的总时间但你感觉页面卡了2秒HAR里可能每个请求都很快。这是因为浏览器并行加载资源多个请求同时进行单个请求的快慢不等于页面的真实体验。页面白屏的瓶颈要看关键渲染路径上的请求顺序以及渲染层的阻塞情况。还有连接复用的问题。当多个请求指向同一个服务器第一个请求完成了TCP握手后续请求的connect和dns可能就是-1。这是正常现象不是HAR坏了。分析时要有这个概念否则你会疑惑为什么有些请求没有建连时间。5.5 content.text缺失或显示不全如果导出的HAR里某个响应只有size和mimeType没有text大概率是你导出时没有勾选“with content”或者这个请求是在录制早期完成的数据没有被完整缓存。Chrome有时会在内存有限的情况下丢弃响应体导致text字段为空。另外二进制的响应内容在HAR中会用Base64编码存放。如果你直接搜索图片的二进制内容会搜不到需要先解码。遇到text很长时某些文本编辑器也显示不了完整内容建议写脚本提取出来单独查看。5.6 不同工具导出HAR的兼容性差异虽然HAR有规范但不同厂家实现并不完全一致。Chrome导出的版本通常是1.2Firefox可能是1.2Charles可能是1.1。字段命名上有些工具保留标准字段有些会增加自定义字段例如Chrome的_resourceType、_initiatorCharles也有自己的扩展字段。解析时不要假设每个HAR都有完全相同的字段最好在代码里用get方式读取并给默认值。如果你要把HAR导入Postman或压测工具还要注意工具的兼容性。例如k6的har-to-k6脚本能自动把HAR转换成压测脚本但生成后的脚本仍然需要人工检查尤其是需要参数化的地方。工具只是辅助核心还是看人能不能读懂数据。5.7 大HAR快速定位的实用命令有时候我不想打开图形工具只想在命令行快速找某个请求直接用jq最方便。比如找出所有状态码大于等于400的条目jq -r .log.entries[] | select(.response.status 400) | [.response.status, .time, .request.method, .request.url] | tsv demo.har再比如按耗时排序取前五慢的请求jq -r .log.entries | sort_by(-.time) | .[0:5][] | [.time, .request.url] | tsv demo.harjq是命令行工具适合在Linux、macOS环境快速处理JSON。Windows用户可以安装Windows版或者直接用Python脚本。我的建议是HAR分析不必拘泥于工具能快速拿到你需要的信息就是好方法。最后再分享一个小技巧我现在每次遇到网络层面的Bug第一反应就是先存一份HAR哪怕最后用不上也好过回头再去复现。上面的经验都是踩过坑换来的尤其是脱敏那条真吃过大亏。希望这篇能帮你少走点弯路。
返回列表