实习第一天,带我的导师丢过来一句话:“把电脑收拾利索,把Charles装上,等会儿联调要抓包看登录接口。”我那时候以为Charles是个什么前端框架,等装完打开才发现,它就是一台架在本机上的HTTP代理服务器,专门用来“看”程序发出去的每一条请求和返回的每一个响应。现在回想起来,win10下Charles的使用几乎贯穿了之后整个实习期:从最简单的抓HTTP接口,到给HTTPS做解密,再到把手机上的App流量拉回电脑排查,每一步都踩过不少坑。
这篇笔记不打算写成官方文档,只记录我在win10环境里从零开始折腾Charles的真实过程。适合刚装好Charles还不知道怎么用的实习生,也适合被HTTPS证书和手机抓包绕晕的同学。整个使用逻辑其实并不复杂,复杂的是你在装证书、开代理、连手机时会遇到的各种“预期之外”的情况,这些恰恰是文档里不会写的东西。
1. 代理调试工具的本质:Charles在win10上到底做了什么
1.1 流量多走一道“驿站”,你才看得见请求的完整链路
要理解Charles,先理解它的工作方式。Charles启动后会在本机开一个HTTP代理服务,默认监听8888端口。只要是经过这个代理的流量,它都会记录下来并在界面上展示。你可以把它想象成一个快递驿站:正常情况下快递员把包裹直接送到收件人手里,现在所有包裹都先到驿站扫描登记一遍,你就能看到包裹从哪来、往哪去、里面装着什么。
对于调试来说,这一道“中转”就是全部价值。请求没经过Charles之前,你只能靠后端日志猜前端发了什么;经过Charles之后,请求URL、请求头、请求体、响应状态码、响应体、耗时全部摆在眼前。前后端联调时双方扯皮最多的“参数对不上”“状态码为什么是500”,用Charles看一眼就水落石出。
win10下Charles接管流量的方式是修改系统代理。启动Charles之后,你打开“设置-网络和Internet-代理”,能看见代理服务器地址变成了127.0.0.1,端口8888。Charles退出时又会把系统代理恢复。这个机制方便,但也有坑:如果Charles不是正常退出的,或者被任务管理器强杀,系统代理可能残留,后面我会专门讲这个坑。
1.2 安装前置条件:JDK版本与端口占用检查
装Charles本身不算难,去官网下载Windows 64位安装包,一路Next就行。真正容易翻车的是运行环境。Charles是Java写的,win10机器上如果没有对应版本的JDK或JRE,双击图标会直接弹“Failed to create the Java Virtual Machine”之类的错误。我自己遇到过一次,当时以为是安装包坏了,后来才发现是机器上Java版本太老。建议安装之前先打开CMD执行java -version,确认版本不低于8。
另外有一个很实际的建议:如果电脑上已经装了Fiddler或其他同类抓包工具,先全部退出再启动Charles。它们默认监听同一个代理端口,两个一起开,轻则一个抓到包一个抓不到,重则直接报端口被占。我实习那会儿就同时开着两个工具,结果Charles报“Port 8888 is not available”,查了半天才发现是Fiddler还挂在后台。
免费版Charles每次启动只能用30分钟,到时间会自动退出。实习期间如果只是临时用,忍一忍也行;如果整个实习期都要靠它联调,建议直接找导师要公司授权,正版许可填进去就省心了。
1.3 启动之后,先搞懂这几个开关再动手
Charles装好启动后,界面乍一看有点懵:左边是空的Session列表,上面一排菜单栏,底部有状态栏。新手最容易犯的错是打开工具之后满心期待看流量,结果列表里空空如也,然后开始怀疑安装有问题。
这时候先看工具栏上的红点。红点是录制开关,只有它亮着,Charles才会记录流量。这个开关特别容易误触,快捷键是Ctrl+Shift+R,记不清什么时候就把它按灭了。红点变灰之后,代理还在,但Charles什么都不记录。所以“打不开抓不到包”,第一件事永远是检查红点状态。
工具栏上还有一个扫把图标,作用是清空当前列表。每次开始新一轮调试之前,我习惯先点一下扫把,把上一轮日志清掉,这样新请求不会被淹没在一堆旧记录里。旁边的乌龟图标是限速开关,放到后面弱网模拟的时候再说。
2. 从HTTP明文到HTTPS解密:根证书与SSL Proxying是分水岭
2.1 为什么默认只能看到CONNECT请求
第一次用Charles抓HTTPS接口时,我盯着Session列表愣了很久:里面确实有请求记录,但全部是“CONNECT www.xxx.com:443”这种格式。没有URL路径,没有参数,没有响应体,完全看不出HTTP请求本来的样子。
这个现象的原因不难理解。HTTPS流量在进入Charles之前已经被TLS加密了,Charles作为中转方,只能看到“你准备和哪个域名、哪个端口建立加密连接”,至于连接建立之后传输的HTTP内容,它是看不到的。列表里的CONNECT记录,本质上只是一条“隧道建立请求”。
想让Charles看到加密内容,就必须做中间人解密:为每个新的HTTPS连接动态签发一张证书,让客户端误以为Charles就是目标服务器,从而在Charles这里完成解密,再转发给真正的服务器。这套机制说起来有点绕,但操作起来不复杂,关键就是两件事:装根证书、启用SSL Proxying。
2.2 win10安装Charles根证书:存储位置比想象中更重要
证书安装路径是:菜单栏Help -> SSL Proxying -> Install Charles Root Certificate。Windows会弹出证书导入向导,一路Next也能装完,但“一路Next”恰恰是后面坑的源头。
证书存储位置必须选“受信任的根证书颁发机构”。如果图省事直接点下一步,Windows可能会把证书放进“个人”存储区,那样浏览器和系统都不会信任它,解密依然失败。我第一次装的时候没注意这个细节,结果Chrome一直报证书无效,后来导师过来看了一眼,摇头说“证书装错地方了”,删掉重装一遍才正常。
装完之后建议验证一下:Win+R输入certmgr.msc打开证书管理器,展开“受信任的根证书颁发机构-证书”,在里面能找到Charles开头的根证书,这才算真正装好。win10上如果浏览器是Chrome或Edge,它们会严格校验证书链,根证书只要不在正确的位置,HTTPS解密就一定失败。
这里多说一句安全提醒:根证书意味着“信任这个CA签发的一切证书”,所以只装在自己的调试设备上。确认不用之后,可以在证书管理器里手动删除,养成习惯没有坏处。
2.3 SSL Proxying的host匹配规则怎么写
装上根证书不代表立刻就能解密,还需要显式告诉Charles“你要解密哪些域名”。打开Proxy -> SSL Proxying Settings,勾选Enable SSL Proxying,然后在Location列表里添加规则。
规则格式不复杂,但很多人写错。我见过最粗暴的用法是直接填一个*,意思是所有域名、所有端口都尝试解密。实习调试阶段这么干确实省事,所有HTTPS请求都能看,但代价是流量多、噪音大,还可能被公司网络的安全策略拦截,所以更推荐按需添加,比如只填api.test.example.com:443。
规则里支持几种常见写法,我后来整理成了一张表:
| 规则写法 | 匹配范围 |
|---|---|
| * | 所有域名所有端口 |
| *.example.com | example.com及其所有子域名 |
| api.example.com | 仅api.example.com这个域名 |
| api.example.com:8443 | 仅该域名的8443端口 |
改完SSL Proxying配置后,很多情况下需要重启Charles,或者取消录制再重新打开录制才会生效。我一开始改完规则傻等半天,以为哪里配错了,其实只是缓存没刷新。另外有个小习惯:规则多余之后及时删掉,避免以后抓包时列表里混入一堆无关流量。
2.4 解密成功后,怎么快速看懂一条接口
解密生效后,Session列表会直接显示请求方法、完整URL、状态码、耗时。点中任意一条请求,右侧Contents区域能看到Request和Response两个方向的内容,响应如果是JSON,Charles会按照格式化视图显示,比看压缩成一坨的原始报文舒服得多。
实习期我看得最多的就是登录接口:选中请求看Form表单或JSON Body里的字段名,再对照后端给的接口文档,马上就能确认参数传对了没有。响应里如果出现中文乱码,优先点右下的Raw视图,看响应头里的charset字段是什么编码,再决定切到什么显示方式。后面我会专门讲乱码处理,这里先不展开。
3. 实习联调最常用的五类操作:Repeat、Compose、Breakpoints、Rewrite与Map Local
3.1 Repeat与Compose:改参数重发请求的两种方式
联调过程中“重发一遍刚才那个请求”是最高频的操作。右键点击任意一条请求记录,选择Repeat,Charles会用完全相同的参数再发一次。这个功能在验证后端是不是偶发问题时尤其好用:你说接口超时,我说刚试是好用的,那就Repeat十次看概率,争论立刻结束。
Repeat原样重发,Compose则允许修改后重发。右键选择Compose,窗口里可以改URL、请求头、请求体,改完点Execute发送。我踩过一个典型场景:后端说登录接口的字段名是user_token,前端代码里写的却是access_token,两边都觉得自己没传错。我用Compose把参数名改成后端说的那个,Execute一发,接口立刻通了,问题定位不超过两分钟。Compose窗口里改完的内容不会被保存成正式规则,适合这种“临时改一下看看结果”的场景。
3.2 Breakpoints:在请求和响应上人为“截停”
Breakpoints是我最喜欢的调试功能,没有之一。它的逻辑是给某个URL设置断点,请求发出前或者响应返回前,Charles都会把流程卡住,让你手动修改Request或Response,改完再放行。
右键一条请求 -> Enable Breakpoint就能设置。之后这条请求再出现时会变成红色,点击Edit Request可以改请求参数,执行完再点Execute放行;响应回来时同理,点击Edit Response可以直接篡改返回的数据。比如接口还没实现某个异常分支,你想测试前端对报错的处理,用断点把响应体改成{"code":500,"msg":"server error"}再放行,前端表现一目了然。
使用断点有两个容易忽视的细节:一是断点规则如果设置成整个域名,那这个域名下的所有请求都会被截停,体验极其酸爽;二是用完的断点规则不会自动消失,需要右键取消或者到Breakpoint Settings里删除。实习时有次我忘了删断点,结果同事跑过来说“接口怎么卡住了”,我一看,自己的断点还在桌上摆着装死。
3.3 Rewrite:把“每次都要改”变成自动规则
Breakpoints适合“偶尔改一次”,但如果“每次都加某个请求头”“每次都要把响应里的字段改掉”,再手动断点就太累了。这时候上Rewrite。
Rewrite位于Tools -> Rewrite,本质是一套“匹配并修改”规则:你可以按Host、URL、Header、Body等维度匹配流量,然后执行修改、添加或删除动作。我在实习里用得最多的场景是:联调环境切换。前端代码里写死了正式环境的域名,后端说“你改成测试环境地址再试”,如果每次手动改代码太麻烦,用Rewrite把请求Host从正式环境域名改成测试环境域名,前端什么都不用动,流量到Charles这里自动被改写。
另一个常用场景是批量加Header。调试接口需要鉴权,每次手动登录拿token太麻烦,就用Rewrite统一在请求头里加上Authorization: Bearer test_token,只要后端不校验token时效,一整天都能顺畅联调。注意Rewrite规则一旦生效,影响的范围是全局的,所以配置完之后要心里有数,别改完忘了关,后面排错时被自己写的规则坑了都不知道。
3.4 Map Local与Map Remote:用本地文件替换线上响应
Map Local的意思是:当请求命中某个URL规则时,Charles不向服务器发请求,而是直接返回你指定的本地文件内容。典型场景是后端接口还没写好,但前端需要先联调页面。用Map Local把接口URL映射到一个本地mock_data.json,前端请求直接拿到假数据,页面照样能跑起来。
配置位置在Tools -> Map Local,勾选Enable Map Local后,添加一条URL匹配规则,指向本地文件路径。这里有个细节:本地文件如果改了,Charles会直接读取最新内容,不需要重启,所以你可以边写mock数据边刷新页面看效果,非常顺手。唯一要注意的是,映射文件路径里尽量别有中文和空格,有些Windows环境下Charles读取映射文件会出问题,表现就是返回404或者数据为空。
Map Remote则是把某个地址的请求转发到另一个地址,适合“把测试环境指到本地开发机”的场景。比如后端同事在本地起了服务,你不想改前端代码,用Map Remote把测试环境域名指向他的内网IP就行。这招在跨电脑联调时很好用,前提是对方机器和你处于同一个内网。
五种操作的适用场景我整理了一下:
| 功能 | 典型场景 | 注意点 |
|---|---|---|
| Repeat | 验证偶发问题、接口幂等性 | 原样重发,不带任何修改 |
| Compose | 临时改参数重发 | 修改不保存,适合快速验证 |
| Breakpoints | 改请求/响应做异常测试 | 规则用完必须删除 |
| Rewrite | 批量换Host、改Header | 全局生效,注意关闭 |
| Map Local | 用本地mock数据替代响应 | 文件路径避免中文和空格 |
4. 手机App抓包:让Android和iOS的流量从Windows这里过
4.1 第一步先解决“同一局域网”和Windows防火墙
Charles能抓电脑上浏览器的流量,但实习里更多时候要抓的是手机App。手机和电脑必须在同一个局域网内:如果电脑连的是Wi-Fi,手机也连同一个Wi-Fi就行;如果电脑插的是网线,可以在win10设置里打开“移动热点”让手机连上。
手机连网之后,进Wi-Fi设置,找到当前网络的代理选项,手动配置:服务器地址填电脑的IP,端口填8888。电脑IP用ipconfig查,一般是192.168.x.x这种格式。填完保存,手机流量就会先经过电脑上的Charles。
这一步最大的拦路虎是Windows防火墙。Charles第一次启动时,防火墙会弹窗询问是否允许它在公共网络上通信,如果你手快点了“取消”,手机端就会全部连接超时。所以弹窗弹出来的时候一定要选“允许访问”,网络类型选“专用网络”。万一错过了,去控制面板的防火墙设置里,把Charles加到允许应用列表里,一样可以补救。
4.2 Android设备:证书之外还有一个版本信任边界
手机代理配好之后,浏览器流量很快就能看到,但App流量大概率还是HTTPS加密状态。Android手机需要用浏览器访问chls.pro/ssl下载Charles证书,然后在系统设置里安装为CA证书。
如果你以为装完证书就万事大吉,那就太天真了。Android 7及以上系统有个默认策略:普通App不信任用户手动安装的证书。也就是说,哪怕你把Charles证书装进手机,大多数App在发起HTTPS请求时依然会校验证书失败,表现就是Charles列表里全是CONNECT,或者App端报SSLHandshake错误。
这个坑不是操作能解决的,需要看App的代码配置。如果是自家公司的App,可以找Android开发同学在工程的network_security_config.xml里,把debug模式配置成信任用户证书。实习生在联调阶段打的通常是debug包,加上这个配置才能顺利抓到App的HTTPS明文。如果只是抓手机浏览器的流量,装证书就够了,因为浏览器走的是系统证书信任链。
4.3 iOS设备:描述文件装完还要再开一个开关
iOS端的证书安装流程比Android多一步。手机Safari浏览器打开chls.pro/ssl,下载一个描述文件,然后到“设置-通用”里找到刚下载的描述文件并安装。这一套流程很多人都会,但装完依然抓不到包。
原因在于iOS 10.3之后的版本,安装描述文件不等于“完全信任”这个证书。你还需要到“设置-通用-关于本机-证书信任设置”里,找到Charles根证书,把“完全信任”开关打开。这一步不做,证书处于“已安装但不受信任”的灰色状态,App和浏览器都不会买账。
iOS端还有一层限制和Android 7+类似:不少App为了安全,只信任系统内置证书,不信任用户手动安装的CA。如果是自家App,可以建议开发同学在debug环境关掉证书校验,或者先用手机浏览器做验证。总之,iOS抓包必备三连:下载描述文件、安装描述文件、打开完全信任开关,三步缺一不可。
4.4 手机流量常见故障:CONNECT刷屏、502、断网
手机配置代理之后,问题不会少,最典型的三个我都遇到过。
第一个是列表里全是CONNECT,看不到具体内容。这说明手机流量确实走到了Charles,但HTTPS解密没有生效。按顺序检查:手机证书装了没、iOS的信任开关开了没、SSL Proxying规则里填了对应域名没。大多数情况是证书环节掉了链子。
第二个是请求返回502 Bad Gateway。这个报错的意思是Charles尝试向后端服务器转发时失败了。先确认电脑能不能正常访问该接口,再检查目标服务器是否拒绝了代理来源的请求。有时候公司网络环境会统一配置HTTP代理,Charles转发时会带上这些外部代理设置,如果外部代理配置错了,也会导致502。
第三个是手机明明连着Wi-Fi,却打不开任何网页。最常见原因是电脑上的Charles已经退出了,但手机的代理设置还指着电脑的8888端口,等于所有流量都发向一个不存在的门牌号。把手机Wi-Fi代理重新设为“无”就恢复了。这是一件小事,但实习期间我已经帮同事解决过好几次。
5. 高频排错笔记:win10里那些让你怀疑人生的坑
5.1 防火墙弹窗误点导致手机全部超时
前面提到过一次防火墙弹窗,这里详细整理一下排错链路。现象是:手机代理配置没问题,证书也装了,但Charles列表里一个请求都看不到,手机端网络一直转圈。
如果你也遇到这个情况,先别急着怀疑代理配置。回想一下Charles第一次启动时,Windows防火墙是不是弹过一个“允许访问”的窗口,你是不是当时点了“取消”。这个动作会直接导致外部设备无法连接Charles监听的端口,手机请求根本进不来。我身边好几个实习生都栽过同一个地方,因为那个弹窗往往伴随着“是否信任此应用”的措辞,下意识就取消了。
解决办法是到控制面板的“Windows防火墙-允许应用通过防火墙”里,找到Charles,或者手动添加Charles的安装目录下的exe文件,然后勾选“专用网络”允许。这里只勾专用网络就够了,公用网络不建议放行,安全一点没坏处。
5.2 端口8888被占用与代理残留
Charles启动时报“Port 8888 is not available”是个经典老梗。排查手段很固定:Win+R打开CMD,输入netstat -ano | findstr 8888,看看是哪个进程占用了这个端口。如果是曾经残留的Charles进程,直接去任务管理器结束掉;如果是其他程序,可以给Charles换一个端口,比如8889,位置在Proxy -> Proxy Settings。
端口占用只是开胃菜,更有迷惑性的是代理残留。Charles非正常退出(比如电脑蓝屏、任务管理器强杀)后,win10的系统代理设置不会自动恢复,还会指着已经无人监听的8888端口。表现是浏览器打开任何网页都报连接失败,但Charles明明已经关了。很多人这时候开始重装浏览器、重启电脑,折腾半天。
正确的处理是打开“设置-网络和Internet-代理”,手动把“使用代理服务器”开关关掉,系统网络立刻恢复。Charles正常退出时一般会替你做这件事,但win10环境里异常退出太常见了,记住这个坑能省下很多时间。
5.3 证书失效:明明装过却突然全部解密失败
有段时间我的Charles表现很诡异:上午抓HTTPS还好好的,下午突然所有请求都变成SSLHandshake错误,手机上的App也集体罢工。检查了代理、检查了SSL Proxying规则,都没问题。最后发现是证书过期了。
Charles的根证书不是永久有效的,到日期之后需要重新下载安装。旧证书不删就装新证书,有时候会在证书管理器里出现两个同名CA,导致系统不知道该信任哪一个。建议处理流程是:先在certmgr.msc里把旧Charles证书删掉,然后重新执行“Install Charles Root Certificate”,装到受信任的根证书颁发机构,重启Charles,问题通常就消失了。
另外有一种情况是系统时间不对。win10如果时间偏了,证书有效期校验会直接失败,表现同样是无解的SSL握手错误。我一同事就是电脑时间慢了半小时,排查了一下午,最后对时重启解决。这种冷门坑平时遇不到,但真遇到了会把你折腾到怀疑人生。
5.4 中文乱码、304缓存与日志刷屏
中文乱码是最容易被误判的问题。Charles的JSON视图里中文显示正常,但切到Raw视图就变成一串Unicode或者乱码。这不是数据有问题,而是显示方式的差异。Raw视图下如果响应头里写着charset=UTF-8,大部分中文都能正常显示;如果接口返回的是其他编码,可以在右键菜单里手动切换字符集。
304状态码也经常把人吓一跳。看到接口返回304,第一反应是“是不是出错被拦截了”,其实304是正常的HTTP缓存行为,表示浏览器本地已有资源,服务器确认资源没变,不需要重新传。真想每次拿最新数据,清一下浏览器缓存再重新请求就行。
最后说日志刷屏。联调高峰期Charles列表里每分钟刷刷刷进来几十条资源请求,JS、CSS、图片、接口混在一起,找自己的请求像大海捞针。我自己的习惯是:在列表底部的Filter输入框里敲API关键字过滤,或者对常用调试域名右键选择Focus,让这些域名的请求置顶并高亮,其他流量自动折叠。这个小技巧让抓包效率明显提升,尤其是接口多到不行的时候,能帮你保住耐心。
最后再分享一点个人体会。实习前两周我基本只用查看和Repeat,后来越用越顺手,才开始把Rewrite和Map Local常态化。刚上手的人我建议按这个顺序练:先不开SSL Proxying,抓一个HTTP网站的请求,把Session列表、请求头、响应体看熟;再装证书开HTTPS解密;最后再连手机。这个顺序能帮你把Charles的每一步功能拆开理解,出了问题也知道是哪一环。一个小技巧是,把常用调试域名右键Add to Focus,列表会清爽很多,接口多的时候非常救命。