ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Charles抓包乱码全解析:SSL、压缩与编码问题修复指南

Charles抓包乱码全解析:SSL、压缩与编码问题修复指南 做接口调试的十有八九都遇到过这种场景端着手机点了半天Charles框体里弹出一串看不太懂的字符——有的像火星文有的全是十六进制堆有的干脆中文变乱码。多数人第一反应是“工具有问题吧换个版本试试”。实际上Charles本身没有坏乱码背后基本都是配置或编码问题。我从接触抓包到现在这类问题遇到不下几十次总结下来就是三件事HTTPS的SSL代理没配好抓到的是密文响应体经过gzip或br压缩在某个环节没被正确解压还有字符集编码不对UTF-8的内容被当成GBK甚至Latin-1显示。这篇文章我会把三种情况的成因、判断方法和完整的修复步骤都写清楚适合刚接触抓包、被乱码卡住的新手也适合已经会抓包但被Android 7以上证书信任问题、模拟器抓包坑过的老开发。1. 先给乱码分个类三种看着像乱码成因完全不同1.1 密文型乱码最常见也最冤枉很多刚上手Charles的人打开HTTPS请求发现里面密密麻麻全是乱码就以为没救了。其实这里面绝大多数情况根本不是乱码而是密文。你想想看Charles抓包本质上是在你手机和服务器之间当了一个中间人。如果HTTPS的SSL/TLS加密流量没有被解密Charles看到的就是一堆加密后的字节流这些字节流放到TextView里当然是一堆乱七八糟的字符。特征非常明显内容看上去毫无规律夹杂着大量特殊符号、不可打印字符请求地址却是标准的https://开头。判断方法很简单点中某个会话看上方Contents区域如果显示的不是你熟悉的JSON、HTML结构而是像“aOU8vZ~#Tq这类无规律字符串那基本上就是SSL解密没生效。这种情况严格来说不算乱码但它用乱码的形式呈现出来很容易误导人。1.2 压缩型乱码和编码型乱码看起来完全不一样压缩型乱码的特征是整个响应体是一个整体性很强的二进制块可能在开头能看到一点点结构比如JSON的大括号或者HTML的标签但后面全是不可读的乱字符。这通常是gzip、deflate或br压缩后没有被正确解压导致的。编码型乱码就好认多了英文、数字、标点完全正常只有中文变成“锟斤拷”“锘挎枃”或者一串方块问号。这种乱码和“密文”有本质区别——你能读懂结构但读不懂中文。典型的场景是服务端返回的Content-Type里没有指定charsetutf-8或者指定了但Charles用错了编码去解码。1.3 三分钟快速锁定乱码类型我过去排查乱码从来不会一上来就动配置而是先做一个三步快速判断先看URL和Headers。URL是https且Response里没有明文特征优先怀疑SSL问题。再看Headers里的Content-Encoding有没有gzip、br、deflate。最后看乱码形态如果只有中文乱那就是编码问题如果整体不可读才是传输内容本身的问题。这三步走完基本就能定位到下面的某一类。接下来我会按照三类分别展开给出具体的排查和修复方案。2. HTTPS密文乱码的完整修复SSL代理与证书缺一不可2.1 原理开关是SSL Proxying钥匙是根证书解决密文型乱码核心就是让Charles成功做一次中间人解密。这需要同时满足两个条件Charles这边打开SSL Proxying开关告诉它“我要解密哪些域名的HTTPS流量”客户端那边信任Charles生成的根证书手机或电脑才会接受这个中间人的身份。这两个动作很多人只知道其一。有人只设置了SSL代理但没装证书结果抓到的还是密文有人只装了证书但忘了开SSL Proxying照样看不到明文。我遇到过不少同事卡了一下午回头看其实是证书装了但Proxy-SSL Proxying Settings里压根没勾选Enable SSL Proxying。2.2 PC端测试的完整配置步骤在电脑上抓包调试配置步骤比较标准我按顺序走一遍打开Charles点击顶部菜单Proxy - SSL Proxying Settings勾选Enable SSL Proxying。在Locations区域点击AddHost填写你要抓包的域名比如api.example.comPort填443。如果你暂时不想区分域名可以直接Host填*、Port填*意思是对所有HTTPS流量做解密。接着安装Charles根证书。菜单Help - SSL Proxying - Install Charles Root Certificate。系统会弹出证书导入向导记得选择“受信任的根证书颁发机构”这一步选错位置等于没装。装完证书再重新发起请求你会发现之前满屏乱码的HTTPS响应已经变成可读的JSON或者HTML了。这里我特别提醒一点如果你Host填了*Charles会拦截所有HTTPS流量包括浏览器里各种乱七八糟的请求每次都会弹窗询问是否允许非常烦人。新手不建议上来就全拦先把目标域名搞清楚只解密你真正需要看的接口。2.3 iOS和Android手机端的证书安装细节手机端抓包是另一个高频场景。iPhone和安卓的信任机制不太一样容易踩坑的地方也不一样。iOS这边配置代理后用手机Safari打开http://chls.pro/ssl下载Charles的证书描述文件。下载完成后到设置里会提示“已下载描述文件”点击安装。这一步装完还不算完很多人在这一步就停了结果发现抓到的HTTPS还是乱码。关键还差最后一步去“设置 - 通用 - 关于本机 - 证书信任设置”把Charles根证书的开关打开让它成为受信任的根证书。这一步不做iOS默认不会信任非系统级CACharles照样解不了密。Android这边流程稍微多一点。配置完代理后用手机浏览器访问http://chls.pro/ssl下载证书文件然后在系统设置里搜“证书”或“加密与凭据”选择“安装证书 - CA证书”选中刚下载的文件。Android 7.0以上系统有个特殊问题后面我会单独讲那是很多App抓包乱码的深层原因。另外提醒一下证书有有效期Charles版本升级后根证书可能变化导致手机突然抓不到明文这时候重新下载安装一遍证书就行。2.4 Android 7以上抓HTTPS乱码的特殊解法如果你用的是Android 7.0以上的设备或模拟器会发现上面步骤全做了但很多App的HTTPS请求在Charles里依然显示乱码或者直接报SSLHandshake错误。原因在于Android 7.0开始系统默认不再信任用户安装的CA证书App如果没有显式配置信任用户证书就会拒绝Charles的中间人证书。针对这个问题的常规处理办法有两个。如果你的App是自己开发的在AndroidManifest里配置networkSecurityConfig明确信任用户证书签名装上就行。如果你测试的是第三方App就只能在可控的测试设备上把Charles证书安装成系统证书常见做法是通过root设备后把证书文件放到/system/etc/security/cacerts目录下。这里要强调一下这些操作都是在你自己控制的测试设备、测试环境下进行的目的就是正常的开发和联调别想歪了。3. 压缩型乱码gzip、br以及断点修改后的坑3.1 Content-Encoding是第一个要看的地方当你排除了SSL问题但响应体还是大面积乱码紧接着就要看响应头里的Content-Encoding字段。HTTP协议里服务器返回大体积数据时常会做压缩最常见的三种是gzip、deflate和br。其中br是Brotli压缩算法近年国内大厂接口用得非常普遍。Charles对gzip和deflate的解压支持比较成熟一般会自动帮你解压但br的支持在不同版本里表现不太一样老版本Charles碰到br压缩的响应就很容易显示成乱码。还有种情况容易被忽略如果你使用的Charles版本太老即使支持gzip在某些情况下也不会自动解压尤其是对chunked传输的响应显示区域依然是一团乱码。所以看到乱码先点选中请求看Headers标签里Content-Encoding的值。如果是gzip、br、deflate那十有八九就是压缩问题。3.2 用外部工具验证压缩响应的原始内容有些时候Charles显示乱码但你没法确认到底是工具显示问题还是数据本身就是乱的。我的做法是脱离Charles用命令行直接请求一次接口看原始返回。比如接口返回是Content-Encoding: gzip可以在终端里执行curl -s --compressed -H Accept-Encoding: gzip, deflate https://api.example.com/getdata--compressed参数会让curl自动解压。如果curl输出正常说明服务器返回的数据没问题是Charles这边解压环节出了问题。如果curl输出也是乱码那就要查服务器返回的数据本身了。再补充一个Python验证姿势用requests库请求它在处理gzip和deflate时是自动解压的import requests resp requests.get( https://api.example.com/getdata, headers{Accept-Encoding: gzip, deflate}, ) print(resp.text[:500])requests能正常打印就定位了问题在Charles端。这种对照法能非常快地帮你排除到底是“数据乱”还是“显示乱”。3.3 断点修改响应后出现的压缩乱码还有一种压缩乱码比较隐蔽发生在你使用了Charles的Breakpoints或Rewrite功能之后。当你拦截到服务器响应手动改动了响应体内容Charles再把这个响应转发给客户端时可能会重新压缩。如果重新压缩的逻辑和原始编码不一致或者压缩流不完整客户端那边就解码失败Charles这边显示也会是乱码。我自己遇到过几次响应头里写的Content-Encoding是gzip我通过Breakpoints改了JSON里的某个字段然后Forward。客户端那边直接解析失败回看Charles里显示的响应体已经乱了。后来我基本不在压缩响应上直接改body而是先用Map Local或者脚本改好再返回。如果你一定要在断点里改建议改完看一眼响应头里的Content-Length和Content-Encoding是不是还一致不一致就手动修正不然客户端解出来就是乱的。4. 编码型乱码UTF-8被当GBK显示以及“锟斤拷”是怎么来的4.1 中文乱码的经典形态分析编码型乱码是三类里面最容易被认错的因为它看起来最像“有点规律可循”的乱码。典型的形态是“锟斤拷”。这三个字几乎是中文乱码界的图腾几乎所有老程序员都见过。它的产生原理不复杂一段本来应该是UTF-8编码的中文文本被错误地按照GBK去解码然后再把解码结果转回UTF-8就会出现这种奇怪的汉字组合。每次看到“锟斤拷”我基本可以直接断言这是UTF-8与GBK之间的编码错乱。另一种形态是“閿涫悊”或者一堆方块加问号那通常是把UTF-8字节流按GB2312或者Latin-1解码的结果。特征是英文正常、数字正常、JSON的大括号和引号正常只有中文部分是乱的。再看响应头里的Content-Type如果写着application/json; charsetutf-8理论上Charles会按UTF-8解码。但很多接口返回的是application/json没有charset字段甚至有些老系统返回text/html这时候Charles就会用内置默认的编码方式去猜猜错了就是乱码。4.2 用Charles的多种查看视图确认编码问题遇到疑似编码问题我习惯先在Charles里切换几种视图信息量很大。选中请求后下面Contents区域有多个标签Text、JSON、XML、Hex等。如果只有Text标签下中文是乱的JSON和XML标签下结构清晰那基本确定是显示编码问题而不是数据问题。更细致的办法是切到Hex视图看中文字符对应的字节。比如一段中文“你好”在UTF-8下是E4 BD A0 E5 A5 BD如果Text视图里显示的不是这个字节对应的可读字符而是别的乱码那就是解码环节出了问题。还有个非常实用的操作右键选中这个请求选择Save Response把响应体保存成本地文件然后用VS Code或者Notepad打开。VS Code右下角可以切换文件编码你把编码从UTF-8切到GBK再切回来能很直观地看到哪种编码下中文是正常的。这个办法可以说是编码乱码的终极判定手段。4.3 正确的修复姿势让Charles按正确编码显示确认是编码问题之后修复要看乱码发生在哪个环节。如果服务端确实返回了正确的UTF-8数据只是Charles按默认编码显示错了最简单的办法是在响应头上下功夫。你可以在Charles里用Rewrite功能把响应头里的Content-Type补充成application/json; charsetutf-8。Charles重新加载这个响应时就会按UTF-8去解码Text视图里的中文就正常了。如果服务端本身返回的就是GBK编码的文本那么就算你补充charsetutf-8也没用反而会更乱。这时候正确做法是保存响应体到本地用编辑器切到GBK查看确认原始字节确实是GBK然后联系服务端同学统一改成UTF-8。说句实话2024年了接口返回GBK的老系统虽然少但银行、政务、传统企业系统里还真能碰到。还有一个小技巧如果Charles里乱码但你急着看某个接口的返回内容可以直接复制这个请求的cURL格式到终端里执行。curl默认按字节输出你再用iconv转码curl -s https://api.example.com/gbk-data | iconv -f GBK -t UTF-8这样哪怕Charles显示有问题你也能拿到正确内容不耽误联调。5. 手机端和模拟器抓包乱码的补充场景5.1 手机上装了证书还是乱码问题出在哪手机端抓包乱码除了前面说的SSL、压缩、编码三类原因还有一个高频场景是证书信任没生效。iOS这边最常见的原因是装了证书描述文件但没在“证书信任设置”里打开完全信任。我见过好几个前端同学描述文件装了代理也配了但抓包还是乱码最后查了半天发现就是漏了这一下开关。Android这边则是App不认用户证书的问题这在老版本Android上几乎是必现的。排查思路也不难先把浏览器流量抓一下比如打开一个HTTPS网页如果Charles里网页内容正常说明代理和证书都通了问题出在目标App对证书的校验策略上。如果浏览器流量在Charles里也是乱码那就说明证书信任链路根本没打通重新走一遍装证书流程。5.2 模拟器抓包乱码的常见原因雷电模拟器这类安卓模拟器抓包有几个容易导致乱码的坑。第一个是模拟器系统版本。新版本安卓镜像默认不信任用户CA你装了证书到用户凭据区很多App依然不认。解决思路和真机一样需要在测试环境把证书放进系统证书目录。这里只讨论技术本身具体操作就是adb推送到/system/etc/security/cacerts下模拟器有root权限就能做。第二个坑是模拟器和宿主机的网络隔离。模拟器里配代理有时候代理地址填的是宿主机IP但SSL握手过程中网络不稳定Charles这边会看到大量异常关闭的连接响应体残缺不全看起来也是乱码。这种情况我一般建议模拟器用“10.0.2.2”这样的特殊地址访问宿主机自带的Charles端口保持一致握手稳定很多。第三个是模拟器里的输入法、Wine容器等本地环境导致的中文显示问题。如果你只是抓包响应体里带中文全部乱码但逻辑数据都对那就不一定是代理的问题也可能和模拟器本身的字体库或者编码环境配置有关。直接导出响应体到宿主机查看用第4节的方法做判定。5.3 模拟器流量乱码的核对方法模拟器里出问题Windows宿主机和macOS宿主机的情况不太一样。最通用的做法还是在模拟器里打开浏览器访问一个返回JSON的HTTPS测试接口如果浏览器里中文正常Charles里正常说明链路没问题。如果浏览器里正常但Charles里乱码优先排查上面说的证书和代理配置。如果浏览器里本身就是乱码那就从系统编码和字体库方向查。之前帮一个同事排查他在雷电模拟器里抓包所有App返回的包都乱码浏览器也是乱码。最后发现是模拟器系统的语言区域设成了非中文系统默认编码不对导致Charles接收到的UTF-8字节流在模拟器内部被转了一次码。把系统语言改成中文并重启模拟器问题就没了。这种问题真机上不会出现但在模拟器里一点也不罕见。6. 常见问题速查表与个人避坑心得6.1 乱码问题速查表我把自己遇到的常见情况整理成一个速查表建议收藏下次遇到直接对号入座症状可能原因处理办法https请求内容完全不可读像随机字符SSL Proxying未开启或证书未安装开启SSL ProxyingPC和手机分别装证书英文正常中文乱码成“锟斤拷”UTF-8被按GBK解码检查Content-Type charsetRewrite补充charset内容整体是二进制块开头有JSON结构gzip或br未解压查看Content-Encoding升级Charles或外部解压修改响应体后客户端解析失败内容变乱断点改压缩响应导致压缩流损坏改用Map Local或修正Content-LengthiOS装证书后还是乱码没有在证书信任设置里打开开关设置-通用-关于本机-证书信任设置Android 7以上App抓包失败或乱码App不信任用户CA证书测试App配置networkSecurityConfig或系统证书模拟器里所有响应乱码浏览器也乱码模拟器系统语言/编码环境错乱改系统语言和编码重启模拟器6.2 我踩过的几次坑第一个坑是混淆了“密文”和“乱码”。早期我抓一个没有配置SSL Proxying的HTTPS接口看到满屏乱码以为是服务端返回了加密数据花了一晚上研究有什么加密算法后来才意识到只是没解密。这个印象太深了从那以后我处理乱码问题有一个固定动作先看URL和Headers再下结论。第二个坑是Charles版本太老。有阵子很多大厂接口全切了br压缩老版本Charles解不了br所有响应全乱码。我当时没有第一时间怀疑工具版本而是逐个研究数据是否有问题折腾了很久才发现升级Charles后全好了。所以遇到压缩乱码先看一眼Charles版本太老就直接升级。第三个坑是在模拟器里排查了半天证书最后发现是系统语言区域问题。模拟器环境变量和真机差异很大很多奇奇怪怪的乱码问题都源于环境而不是数据。从那以后我养成了一个习惯遇到乱码先导出响应体在宿主机用编辑器切编码看确定数据本身没问题再回头翻工具配置。6.3 一个延续多年的排查习惯最后分享一个我用了很久的小技巧。每个被我认真排查过的乱码响应我都会右键Save Response存成文件然后在VS Code里按不同编码切换一遍。这个动作花不了三十秒但能一次性区分开密文、压缩、编码三大类问题效率极高。你不用每次都做但当你被某个乱码卡住超过十分钟这个步骤一定能帮你重新定位方向。我的经验是Charles抓包显示乱码九成是配置问题一成是数据本身的问题。先把“数据乱”和“显示乱”分开再按这篇的思路逐项排查基本都能快速解决。不要动不动就怀疑工具坏了Charles这种老牌工具在解码这件事上还是相当稳定的问题多半出在我们对它的配置还不够熟。
返回列表