首页
/
行业洞察
/
正文
INDUSTRY INSIGHT · 深度
Charles抓包乱码不再难:从Gzip压缩到字符编码的完整排查指南
📅 2026/10/5 15:33:53
✍️ 爱科研究院
👁 阅读 3,247
做客户端开发或者接口联调的人基本都被Charles的乱码折磨过。明明请求发出去没问题接口文档里也写了返回JSON可Charles的Response面板里就是一堆看不懂的字符——有时候是成片的方块有时候是夹杂着问号的半截中文还有时候干脆是一坨压缩过的乱码复制到任何编辑器里都还原不出原文。这篇文章不会讲太多虚的直接围绕Charles抓包显示乱码这个具体痛点上干货。我会把乱码产生的几个真实原因拆开讲清楚再给出一套从设置、编码、压缩到证书配置的排查流程最后附上一份可以直接照抄的问题速查表。无论是刚装好Charles的新手还是被模拟器和小程序抓包折腾过的老手这篇文章都能帮你省下不少排查时间。1. 乱码不等于乱码先搞清楚Charles里那串乱码到底从哪来很多人在网上搜Charles抓包乱码搜出来的答案五花八门有人说要改编码有人说要装证书还有人说是Charles版本问题。其实这些回答都对但不完整。因为乱码只是一个笼统的现象描述背后至少有三条完全不同的产生路径对应的解决办法也完全不一样。1.1 三种常见的乱码长相与对应来源我做了这么多年联调见到的Charles乱码大致可以分成三类你看一眼现象基本就能判断是哪一类。第一类是中文变成问号或者方块。比如接口返回的是{name:张三}Charles里显示成{name:???}或者{name:锟斤拷}。这种是典型的字符编码问题通常发生在响应头没有正确声明charset或者服务端返回的编码和Charles默认解析的编码不一致时。最经典的场景是老的Java服务端用GBK输出Charles用UTF-8去解结果就是一堆锟斤拷。第二类是内容整体变成一行或几行没有空格的乱码看起来像浓缩的加密字符串。这种情况十有八九是压缩响应——服务器返回了Gzip压缩过的数据但Charles没有自动解压直接把压缩后的二进制流展示成了文本。HTTP协议里服务器为了减小传输体积经常对JSON、HTML这类文本资源做Gzip压缩如果抓包工具不解压你看到的就是压缩流的原生态乱码。第三类是整个Response面板显示加密串但Preview里能看到内容。这种情况出现在HTTPS接口上多半是SSL证书没有正确配置Charles只能看到密文。严格来说这不叫乱码叫没解密但很多人的第一反应就是乱码了然后跑去改编码设置折腾半天没用。这三类现象在同一个接口上还可能叠加出现——比如一个Gzip压缩且编码为GBK的HTTPS响应你看到的乱码就可能是压缩流、编码错误、SSL解密失败三者混合的结果。所以排查的第一步不是急着百度Charles 乱码怎么解决而是先判断当前这个乱码长什么样、属于哪一类。1.2 源头排查抓包过程本身就会引入乱码的环节除了服务器返回的字节本身有问题抓包链路里的每个环节其实都可能引入乱码。我见过不少项目组客户端、服务端反复确认接口没问题最后锅竟然在Charles的配置上。抓包链路大致是客户端发出请求 → Charles作为代理接收 → Charles转发给服务器 → 服务器返回 → Charles接收响应 → Charles在界面展示。这个链路里有几个环节会导致显示乱码但实际数据正常Charles展示层的问题最容易被忽略。Charles的Response查看器默认会根据响应头里的Content-Type做展示。有些老接口的Content-Type写的是application/octet-stream或者压根没写Charles就会用十六进制或者纯二进制形式展示看起来当然就是乱码。这时候其实数据没问题换个展示方式就好。Charles的解压层问题前面说过了。Charles理论上会自动处理Content-Encoding为gzip的响应但如果你用了较老的版本或者Charles在代理过程中没正确处理响应头它就会把压缩流原样展示。Charles的解密层问题则绕不开证书。Charles抓HTTPS的原理是中间人替客户端做证书校验如果客户端没信任Charles的根证书Charles就无法解密TLS流量界面里显示的只能是密文。我在实际排查时有个习惯先用命令行工具直接请求同一个接口和Charles的抓包结果做对比。如果curl能正常看到中文Charles里是乱码那问题基本就在Charles的展示或解压层如果curl看到的也是乱码那问题就在服务端返回的数据本身。这个对比法能帮你快速缩小排查范围省掉一大半无用功。2. 为什么Gzip压缩响应永远是最常见的乱码元凶坦白讲我遇到的Charles抓包乱码求助里至少六成是Gzip压缩导致的。这个比例高到什么程度呢基本每次有同事截图问我Charles乱码了我瞄一眼响应体——如果内容看起来像一行被折叠过的、没有空格的、夹杂着特殊符号的字符串我都不用看第二眼直接让他检查Content-Encoding。2.1 Gzip在HTTP协议里的运作方式要理解为什么压缩会导致乱码需要先明白HTTP压缩的过程。服务器在返回大体积文本时会在响应头加上Content-Encoding: gzip然后把原始文本用Gzip算法压缩后传输。浏览器和抓包工具收到后看到这个响应头就能自动解压把原始文本还原出来。问题就出在看到才能解压这五个字上。Charles正常会自动解压但有几个例外情况会让它看不到或者不去看这个响应头重定向响应。有些接口先返回302Location指向真正的资源地址。Charles对重定向的展示有时候会保留原始压缩流导致你看到的是一条302响应里的压缩乱码。非标准Content-Encoding值。个别服务器会写Content-Encoding: x-gzip或者大小写不规范Charles对这种非标准值支持不够好就不会主动解压。Charles版本太老。这个真的不是玄学老版本Charles对HTTP/2协议下压缩响应的处理确实存在问题。我印象里Charles 4.2之前对某些HTTP/2 gzip流的解压是有bug的后来版本才修复。代理链路上的中间设备。如果你在公司网络里用了其他代理工具或者Charles开启了外部代理转发中间层可能已经把Content-Encoding头剥掉了但没解压bodyCharles拿到手的是一个没有解压提示的压缩流自然只能当乱码展示。2.2 Charles解压缩机制与正确设置步骤按正常逻辑Charles收到带Content-Encoding: gzip的响应后会自动解压不需要用户额外配置。但如果你确定响应头里有gzipCharles还是显示乱码可以按下面这套顺序排查和设置。第一步在Charles里确认响应头真的完整。点击Response面板上方的Headers标签找到Content-Encoding这一项。如果能看到gzip说明Charles确实收到了压缩标记。如果看不到但body明显是压缩流那就是中间环节把响应头吃掉了需要检查代理链路。第二步检查Charles的展示方式。切到Response面板在左下角的查看方式里选择JSON或者Text不要选Hex。我见过有人一直在Hex模式下看十六进制非说乱码其实是没切对视图。第三步强制Charles忽略编码头并手动解压。如果确认是Charles自动解压失败可以试试在Proxy → SSL Proxying Settings里调整设置或者干脆把响应体复制出来用外部命令手动解压验证# 假设你把乱码响应体存成了 body.bin # 先尝试直接用curl请求看能不能正常解析 curl --compressed -H Accept-Encoding: gzip http://your-api.com/xxx # 如果需要手动解压检查文件头是否为 gzip1f 8b file body.bin # 如果不是gzip格式尝试用python自动识别并解压 python3 -c import gzip, sys with open(body.bin,rb) as f: data f.read() if data[:2] b\x1f\x8b: print(gzip.decompress(data).decode(utf-8, errorsreplace)) else: print(data.decode(utf-8, errorsreplace)) 这一步能帮你确认到底是Charles不给你解压还是服务器返回的压缩流本身就是坏的。如果是坏的压缩流Charles再努力也解不出来这时候要反过来找服务端的问题——有些服务端框架在压缩大响应时会截断数据或者压缩流没写完就flush了这些会导致Charles显示莫名的乱码但curl因为容错机制反而能正常显示。注意如果你在Charles里看到的压缩乱码是一段以H4sIAAAA...开头的Base64字符串那是Gzip压缩后再Base64编码过的内容通常出现在某些框架的响应体里。这种不是Charles不解压是服务端主动做了两次编码。遇到这种情况用echo 内容 | base64 -d | gunzip命令就能还原。3. 从字符编码角度解决中文乱码问题聊完压缩再来看字符编码。这一块是中文乱码的重灾区也是最容易让人绕圈子的地方。其实字符编码乱码的本质很简单Charles拿一种编码去解释另一种编码产生的字节。3.1 HTTP响应里的编码声明与Charles的展示逻辑HTTP协议里响应体的编码是通过Content-Type头里的charset参数声明的。比如Content-Type: application/json; charsetutf-8就告诉接收方这个body是UTF-8编码的JSON。Charles拿到响应后会优先看这个charset用它来解码body并展示。最常见的编码乱码场景就是服务端声明的是charsetutf-8但实际返回的却是GBK的字节流。这种不一致通常不是故意的而是服务端框架内部处理流时默认用了系统编码。Java服务端在Linux环境默认UTF-8还好如果是Windows环境且代码里没显式指定编码就容易出现声明UTF-8、实际GBK的诡异情况。Charles严格执行了charset声明按UTF-8解码结果看到的就是一堆锟斤拷、烫烫烫这类典型乱码。反过来还有一种场景响应头没声明charset。很多HTTP框架在返回纯JSON时不会自动加charset参数只写Content-Type: application/json。Charles拿不到明确的编码声明就会使用默认的UTF-8或者ISO-8859-1去猜。ISO-8859-1解码任意字节都不会报错所以你会看到一串Latin字符集样式的外文乱码而不是中文。3.2 强制字符集覆盖与响应体处理技巧知道了原理解决思路就清晰了。你可以尝试两种路径一是强制Charles按正确的编码重新解析二是把body导出后转换编码。Charles本身没有提供强制指定解码编码的图形化按钮这个问题很多人搜不到答案因为确实藏得深。变通方法是用Charles的Tools → Rewrite功能在响应头里强行改写Content-Type加上charset。这种方案比较重型需要配置Rewrite规则而且会影响所有匹配的请求适合处理固定接口的长期问题。更推荐的做法是导出body后用工具转换编码顺序是在Charles里右键目标请求 →Export→ 选包含响应体的格式HAR文件然后用Python读取并转码。HAR文件里body默认是Base64编码的你可以先解码出原始字节再按正确编码还原import json, base64 with open(charles_dump.har, encodingutf-8) as f: har json.load(f) # 遍历所有条目这里取第一个有响应体的示例 entries har[log][entries] for entry in entries: resp entry[response] if resp[content].get(encoding) base64 or resp[content].get(text): # text 字段直接是体能内容但注意HAR里保存的text可能已经是字符串 # 更稳妥的做法是拿原始base64去解 raw_b64 resp[content].get(text, ) break # 手动解base64并按GBK/UTF-8尝试还原 raw_bytes base64.b64decode(raw_b64) for enc in [utf-8, gbk, gb18030]: try: print(f {enc} ) print(raw_bytes.decode(enc)) break except UnicodeDecodeError: continue这段脚本是我实际排查乱码问题时的万能钥匙。不管Charles里显示成什么样子只要拿到原始字节挨个编码试一遍总能找到正确的解码方式。此外关于Charles的Window → Display Settings里面有个Font设置可以调整响应体展示字体。有些乱码其实不是编码问题而是字体不支持中文导致显示成方块。Windows上Charles默认用的字体有时候对中文支持不好换一个中文字体比如Microsoft YaHei微软雅黑就能解决。这个点很少人提到但确实会让人误判为乱码。提示排查中文乱码时可以先做一个简单的对照实验。在Charles里随便找一个返回中文且显示正常的接口然后对比乱码接口的响应头。如果正常接口的Content-Type里有charsetutf-8乱码接口没有那基本可以锁定是编码声明缺失的问题。4. 手机端与模拟器环境下抓包乱码的联调排查如果只是电脑端的Charles抓网页接口乱码问题相对单纯。但很多人的乱码场景发生在手机抓包、小程序抓包、或者安卓模拟器抓包时这时候问题的复杂度会明显上升因为多了证书、网络代理、应用层校验好几个变量。我单独把这一块拿出来讲就是因为在Charles抓包乱码的搜索词背后大量的实际诉求是移动端联调。4.1 证书配置阶段的乱码表现安装证书前抓HTTPS的乱码幻觉先说一个高频现象手机刚连上Charles代理还没来得及安装Charles根证书就去抓一个HTTPS接口发现Response里全是乱码或者显示SSL handshake failed。很多人以为这是乱码其实是没解密。Charles抓HTTPS的原理是中间人模式。手机把请求发给CharlesCharles和服务器建立真正的TLS连接然后用另一个伪证书和手机建立TLS连接。这个伪证书必须被手机信任否则手机的TLS库会在握手阶段直接拒绝根本不会有流量到Charles的解密层。所以你在界面里看到的乱码要么是一次握手失败的提示噪音要么是最早期的明文协议部分比如TLS握手前的ClientHello。解决这个乱码幻觉的方法是完整的证书信任流程电脑端Help → SSL Proxying → Install Charles Root Certificate在电脑钥匙串里信任Charles根证书。手机端设置WiFi代理指向电脑的IP和端口默认8888手机浏览器访问chls.pro/ssl下载证书文件。安装证书后还需要在Proxy → SSL Proxying Settings里勾选Enable SSL Proxying并添加需要解密的域名规则。很多人忘了这一步导致证书装了但HTTPS流量依然不解密。证书配置完成后还有一个容易忽视的点安卓7.0以上的系统默认不信任用户安装的证书。这意味着就算你在设置里手动装了Charles根证书App如果用了Network Security Config显式禁止用户证书Charles依旧解不了密。这种场景下抓包工具里只会显示SSL handshake failed或一段TLS密文乱码。解决办法是检查App的AndroidManifest里是否配置了networkSecurityConfig如果有需要配合调试包或者root环境处理。4.2 雷电模拟器14配置要点雷电模拟器在相关热搜词里出现了很多次它本身是个很常见的抓包环境。雷电模拟器14跑抓包时有几个坑很容易导致Charles乱码我一个个说。第一个坑模拟器里的网络模式问题。雷电模拟器默认使用NAT模式但如果你改成了桥接模式模拟器里的IP会变得和宿主机不一致Charles的代理设置就会失效抓到的流量可能直接是加密原样。建议在模拟器设置里使用NAT模式然后在模拟器的WiFi设置里手动配置代理指向宿主机的局域网IP:8888。第二个坑模拟器里的TLS版本太低。有些老App在模拟器里的TLS实现比较旧服务端证书链验证会失败Charles虽然能解密但响应的某些环节会出现异常字节。这种问题一般升级Android版本镜像能解决雷电模拟器14默认镜像一般没问题但如果你用的是旧镜像就要注意。第三个坑模拟器App不响应代理。部分App比如某些小程序框架不走系统代理Charles根本抓不到包你看到的乱码可能是Charles里完全没有这个请求或者只有一条CONNECT记录。这时候需要用Charles配合代理转发工具比如把流量转到Charles监听的端口或者使用模拟器里的VProxy方案。这里不展开讲但你要知道抓不到和乱码有时候是同一个问题的两种表达。移动端乱码排查还有一个细节把响应体的Charset信息在Charles里的Note或者Breakpoints模式下看。特别是在调试接口时如果发现同一个接口在模拟器上正常、真机上乱码优先考虑是不是手机系统和模拟器的默认编码不一致。这种情况很少见但我确实遇到过——一个App在模拟器上用了系统默认编码GBK在真机的UTF-8环境里反而乱码最后是改服务端响应头强制charsetutf-8才统一解决。注意抓包App或小程序时如果Charles里看到的是HTTP/2的二进制帧乱码看起来是有规律的二进制块这不是真乱码是HTTP/2协议的frame header。Charles对HTTP/2的展示没有HTTP/1.1那么成熟建议在Charles的Proxy → Settings → HTTP里把Use HTTP/2相关的兼容选项开启或者让服务端主动降级为HTTP/1.1调试。5. Charles常见乱码问题速查表与避坑笔记前面几章是为什么和怎么办这一章我把常见的乱码场景、判断特征、解决方案整理成一张速查表适合你排查时直接对照。同时我会补充几个Charles本身安装、汉化、注册阶段的伪乱码问题——你没看错安装和汉化过程里也会遇到乱码这些在搜索热词里同样高频出现。5.1 乱码场景问题速查表现象特征最可能原因首选解决方案备选方案中文变成???或方块响应头charset缺失或错误检查Content-Type charset导出body按GBK/UTF-8转码用Rewrite改写响应头加charset内容是一行无空格乱码Gzip压缩流未解压检查Content-Encoding是否为gzip导出后用gzip.decompress还原以H4sI开头的字符串Gzip后Base64编码用base64 -d再gunzip还原检查服务端是否二次编码HTTPS接口整段密文SSL证书未信任或SSL Proxying未开完整安装证书并勾选Enable SSL Proxying检查Android 7.0用户证书信任显示正常但中文是方块Charles字体不支持中文改Display Settings里的Font为微软雅黑换皮肤或升级版本响应体是十六进制Content-Type为octet-stream切换Response视图为JSON/Text服务端修正Content-TypeWindows模拟器下中文全乱系统区域语言不是UTF-8改系统区域设置勾选Beta版UTF-8在模拟器里调语言与输入法设置下载的Charles汉化包乱码汉化补丁编码格式问题换官方原版避免第三方汉化手动设置界面语言为English导出的HAR文件中文乱码HAR保存时编码处理不一致使用Python脚本读取并转码用指定编码重新打开HAR文件这张表里的每一条我都至少在真实项目里验证过一次。其中响应体是十六进制这条值得多说一句有些接口的Content-Type虽然是JSON但服务端代码里错误地设置了application/octet-streamCharles会默认以二进制方式展示。很多人不知道这个逻辑以为自己接口返回乱码了其实只是视图模式的问题。5.2 下载安装、汉化与注册过程中的乱码歧义搜索热词里出现了一堆和Charles乱码无关但看起来很像的词比如charles中文版下载、charles汉化、wine 乱码、linux 解压文件乱码。这些词为什么会和Charles抓包乱码关联在一起我推测是用户在搜索charles时遇到了别的乱码问题或者把Charles的安装、汉化过程的乱码和抓包乱码混在一起搜了。这里简单澄清一下帮你快速区分。如果你是在下载或安装Charles的时候看到乱码那大概率是安装包的编码问题或者系统区域设置不支持中文导致的。这种情况正常抓包功能不受影响乱码仅限于安装界面。建议直接下载官方原版安装包安装时选择英文界面汉化补丁如果来源不正规不仅可能乱码还可能引入安全风险不建议个人开发者使用。如果你在Linux环境用Wine跑Charles时遇到乱码那基本是Wine的字体和区域设置问题典型表现是整个界面文字错乱。这跟HTTP抓包完全无关是Windows应用在Wine环境下的中文渲染问题。解决方案是给Wine安装中文字体或者调整Wine的locale设置。如果你在Linux下只是想抓包其实还有更轻量的命令行方案不一定非要跑Charles。另外还有一个词值得注意charles注册。Charles如果处于未注册状态每30分钟会退出一次有些用户在重开Charles之后看到Response面板异常也会觉得是乱码。这其实是会话数据丢失导致的显示问题和字符编码无关。注册Charles是付费行为这里不展开讨论但你要知道未注册版本的会话不稳定可能引发各种奇怪显示问题。5.3 进阶建议导出HAR文件后二次解析遇到Charles怎么调都还是乱码的情况不要死磕界面换个思路把抓包结果导出成HAR文件用脚本做二次解析。HAR文件本质上是一个JSON格式的文件记录了每一个请求和响应包括响应体的Base64编码内容。只要你拿到了HAR文件就等于拿到了原始字节后续用什么编码还原、怎么解析都是你的自由。我处理过最棘手的一个案例是这样的某支付接口在Charles里始终显示为一段无法还原的乱码连导出后用Python都解不出来。后来我用HAR文件里的response.content.text字段HAR标准里会保留一个文本版本再配合服务端返回的Content-Length做对比分析发现是服务端在返回JSON时多写了一段二进制BOM头前面的解码器被BOM干扰了。找到根因后让服务端去掉BOM问题就解决了。这种问题如果只看Charles界面一辈子都排查不出来但导出HAR后数据是完整的任何异常都逃不过分析。所以我最后的建议是除非你只是临时看一眼否则抓包乱码问题尽量用HAR导出脚本解析的方式来定位。这不只是因为Charles的展示层可能失真更重要的是HAR文件可以脱离Charles独立分析方便你带着数据去问同事、贴到工单、或者用其他工具二次验证。个人经验总结踩过这么多年Charles乱码的坑我最大的体会就是乱码从来不是单一原因一定要先判断现象再动手改配置。很多人一遇到乱码就去搜Charles 设置编码结果设置了半天发现其实是Gzip压缩流没解压方向完全跑偏。我自己现在的排查顺序基本固定了先看是压缩流还是中文问题再看响应头有没有Content-Type和charset然后看是不是HTTPS证书没配置好最后确认不是Charles字体和视图模式的问题。这套顺序走下来90%的乱码都能在五分钟内定位。如果你按照这篇文章的模块逐项排查还解决不了大概率是服务端返回的数据本身有问题——这时候别折腾Charles了直接拿着导出的HAR文件去找接口负责人一起看吧。
📌 标签:
工业官网
设计趋势
AI 建站
SEO
获取完整报告 →
RELATED ARTICLES
推荐阅读
2026/10/5 15:33:53
Python+CNN图像识别实战:从数据预处理到模型训练全流程
2026/10/5 15:33:53
DDD驱动的微服务API重构:从语义失控到优雅落地的实战指南
2026/10/5 15:33:53
Smartstore AI图像生成:文生图、背景移除与图像合成全解析
2026/10/5 20:34:10
flutter开发vscode插件推荐(开发必备):用TaoToken统一Key打通AI补全与调试链路
2026/10/5 20:34:10
ROS2+SLAM+Nav2全栈实战:用树莓派打造自主移动机器人
2026/10/5 20:34:10
openclaw-lark 源码架构深度解析:Channel、Tools、Messaging 三大核心模块的设计思想
2026/10/5 20:34:10
2026 年开源 Agent 工具包选型指南:延迟、审计、可移植性与语言栈
2026/10/5 20:34:10
从2节点到8节点集群:spark-vllm-docker的DGX Spark组网拓扑完全指南(直连、3节点Mesh、交换机)
2026/10/5 20:29:10
Codex 全自动视频剪辑实测:从素材到成片,TaoToken 统一 Key 能省多少步?
2026/10/5 0:02:57
AZ-104题库深度拆解:从刷题到掌握Azure管理员核心考点
2026/10/5 0:02:57
WorkBuddy:基于MCP协议的组织级工作流神经中枢
2026/10/5 0:02:57
大模型 / AI 应用常见面试题及答案汇总(2026 最新版):用 TaoToken 统一 Key 跑通高频考点代码验证
2026/10/5 4:43:56
Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化
2026/10/5 1:10:25
多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系
2026/10/5 13:05:37
hindsight:面向LLM应用的事后可观测性工程实践
2026/10/5 20:28:25
我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
2026/10/5 20:28:23
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026/10/5 20:28:21
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)