美文网首页
Analyze HTTP traffic in Instrume

Analyze HTTP traffic in Instrume

作者: 今天写明天改 | 来源:发表于2021-07-08 18:53 被阅读0次

    前言

    今天和大家分享WWDC2021的HTTP流量分析的技术,通常我们会在一些抓包工具里处理自己的应用网络数据分析
    那么。但是,这些工具如何和我们的代码结合在一起呢,WWDC2021引入了新的HTTP traffic in Instruments,如图


    HTTP Traffic Instrument

    我们可以看到,还是很像之前的Network工具的。
    实际上,今天介绍的13版本工具集中的HTTP 流量工具它包含在之前的Network模版中,可以帮助我们理解API和请求生命周期的关系

    1. 它适用于所有苹果设备
    2. 整个穿过URL 加载系统的流量都会曝光、甚至是HTTP/3或者是VPN
    3. 以framework级别集成在系统中
      ○ 过程以属性方式表达
      ○ 磁盘缓存请求
      ○ 揭示网络错误
      ○ 熟悉的高层API

    篇章结构

    介绍的内容分两部分:
    第一部分:主要解释工具的UI如何反映你正在使用的API内容
    第二部分:通过4个例子来解决性能和正确性问题

    第一部分: 工具UI概览

    HTTP Traffic Instrument

    首先介绍导航,导航是围绕轨迹堆栈构建的
    HTTP流量工具在最顶层(红色区域),展示任意时间APP中有多少任务,非常适合在应用程序生命周期中检测HTTP流量活动增加的点。
    下一层次结构(绿色区域)显示了按进程划分的活动。 不仅有所有可调试的过程产生的流量,还有由它们初始化的后台流量
    每个进程下面都包含它使用的所有URLSession。这些对应于在代码中创建的URLSession对象。
    橙色的这一部分是每个session和它们的独立任务,为了更好的将代码和可视化结合起来,允许我们查看每个独立的任务间隔,可以在代码中将session实例命名,可以通过如下的代码来实现
    let session = URLSession(configuration: .default)
    session.sessionDescription = "Main session”
    最后一个是按照域名分类的任务信息,这里会展示任务的状态
    例如,上图的蓝色部分就是一些task 从选中的域名在加载数据

    单个Task分析

    我们来分析一个task


    单个task的信息

    这个任务间隔有很多的信息
    我们可以以一个更抽象的方式来重新表示这张图,来理解工具的可视化如何映射到使用的API
    我们把它简化成第二张图


    task信息抽象表示
    最顶层的是一个task 也就是绿色的部分
    Task 是由一个或者多个事务组成的 每个事务是由 一对HTTP请求和响应组成的

    任务API与UI对应

    API与UI的映射

    Task 是代表了你的代码如何与URL加载系统API进行交互 当我们创建一个task 并调用它的resume方法,这个task 间隔就开始了而当你的completion Block被调用的时候这个间隔就结束了
    每个task都可以给一个semantic语义名称,通过使用taskDescription属性,这个属性会在工具中来标记任务间隔

    任务描述

    任务label的描述

    每个task都可以给一个semantic语义名称通过使用taskDescription属性 这个属性会在工具中来标记任务间隔

    任务标识

    任务label的标识

    同时我们也会在task label 上显示task的identifier 这允许我们将任务与其他数据交叉引用

    任务发生错误

    任务label描述错误

    当任务失败的时候,错误的提示会打印在间隔的label上 这使得我们更容易调试 下面我们来看 一个任务包含多个事务的情况

    Task 有多个事务

    包含多个事务的task
    这是一个加载APP首页的任务 左边我们请求了一个apple.com 但是实际上它的网址是 www.apple.com 这个时候服务器返回重定向,系统会重新初始化一个新事务以加载首选URL 第二个成功的响应就是task的返回
    它与URLSession在底层处理任务的功能一致

    任务Label内容的结构

    任务Label内容

    如前所述:任务Label表示了URL加载系统处理的请求 + 响应对
    其中包含了所有的HTTP层的信息:
    URL, HTTP版本,连接,缓存信息
    请求 + 响应头
    请求 + 响应体

    Transaction 信息概要

    Transaction信息概要

    就像任务一样,事务的label也是展示一个概要,基本上,我们可以找到请求和响应两部分,导航结构会显示域名,可以在请求部分找到路径、请求参数, 例子中的信息依次是HTTP的version、method、请求里是否携带了认证头部和cookie 头部。对于响应,我们会看到 status code 例如上面的200 ,还有响应里是否携带了set-cookie 头部,最后是content-type的内容。 请求和响应花费了多长时间。以及关于事务其他部分的详细时间信息都会在存储在事务的状态里。接下里我们分析一下这个内容

    不同阶段的时间

    事务不同阶段的时间

    Transaction 的起始是transaction被创建的时候。 它首先会检查我们是否已经有了一个合法的缓存如果没有,它就会在一个connection上开始一个新的请求,接下来 transaction 可能会等待一段时间来等一个可用的连接, 当请求被连接处理之后,发送请求的阶段就开始了,这一阶段持续到我们把请求的最后一个比特发送出去 然后transaction 进入一个空闲的状态,等待响应然后接收响应,该响应将跟踪从服务器收到的第一个字节到最后一个字节的跨度,整个事务将在收到最后一个字节后的很短时间内结束
    事实上, 缓存查找和发送一个GET请求要比图中短很多 所以实际上的时间段看起来就像这样


    实际的事务不同阶段时间

    接下来我们进入第二部分:实例

    第二部分:实例

    用HTTP Traffic工具验证APP

    让我们来用HTTP Traffic工具验证下APP来帮助我们改善这种状况 在Product菜单中我选择Profile来在工具中分析APP 这会使用release 配置,开启了全部的优化来构建我的APP,以确保我的应用程序能够像我用户运行的那样进行评测。 构建完成后,工具会自动启动,启动后就会看到标准的工具选择界面,我们选择Network模版


    使用Profile验证APP

    Network 面板

    Network面板

    下边的是已有的流量分析工具,上边是新的HTTP Traffic工具。我们主要集中在上边这个工具 只要我们点击record 工具就会启动APP并开始记录,当然 开始使用这个工具之前需要确认你理解捕获网络流量的含义 工具会抓获很多数据尤其是你决定捕获所有进程 即使是用户凭据,所以你应该对结果追踪文件非常小心

    显示所有的事务间隔

    接着让我们使用option click 和拖动放大数据确保包含我们HTTP traffic的区域


    展开追踪区域

    我们也可以像图片一样在左侧点击向下展开,增加追踪区域的高度,来显示所有的事务间隔

    实例1

    想象我们有一个专门展示图片的类似社交媒体的APP,用户可以上传图片,并且获得一连串最近的上传图片 当加载一系列图片的时候,我们会注意到等全部加载完会花费一些时间,为了分析这个问题我们打开HTTP Traffic面板

    列表加载过程.png
    在这张图片上 左侧的第一个是请求服务器最近图片列表的任务,当这个任务完成后 我们会创建一个新的任务,加载列表中每个用户看到的(thumbnail)缩略图 现在在它所占用的时间帧区域上点击拖动来获取图像列表 这后边会跟着许多请求来获取每个图片
    查看整个过程的耗时
    如图当我们拖动的时候会显示选择的时间范围总共多长时间, 可以看到整个过程占用了超过7秒钟来完成加载初始化的屏幕
    事务的完成时间
    前面的一些图片加载比较快,但当我向下滚动,后面启动的任务完成所需的时间会更长
    这从图中增长的紫色blocked状态条可以看出。
    看起来像是因为竞争问题,我们这里有太多的并行的请求,我们不妨探究一下后边的某个任务 鼠标悬停在上边就可以看到工具的关于任务和它任何子环节的时间间隔提示 可以看到这个任务大部分时间都被阻塞了
    为了理解为什么被阻塞了,我们可以查看左侧域名下的向下展开的箭头
    选择 HTTP Transactions by Connection项
    如图所示,可以看到当前选择的是绘制任务, 我们切换到 HTTP Transactions by Connection
    HTTP Transactions by Connection视图
    这个视图将事务按照它们使用的连接而不是按照任务来将它们分类 我们可以找出它们被调度到哪个连接 总体上,这里有6个连接可以处理这些事务,我们来分析connection1上的事务问题,并进一步探索一些缩略图的加载
    从上而下事务完成的时间越来越长, 每个成功的事务的紫色阻塞状态都在增加 事实上,这里有一个很清晰的阶梯部分在这里
    事务的阶梯完成状态
    每一个任务都会在同一个连接的之前的事务完成之前等待。只有这样才能发送它自己的请求,也就是图中每一个事务的灰色部分的开始和上一个的灰色部分的结束是对齐的,这个模式会在每一个后续的事务上重复, 这也就是我们说的线路阻塞,这也是使用HTTP1的问题。令人沮丧的是,这些事务大部分时间都不做任何事情,它们大部分时间都在阻塞和等待服务器的响应,我们可以在事务等待同一个连接的上一个事务的请求响应的时候发送新的请求 ,但是HTTP1并不支持这些,线路阻塞是http的主要问题之一,http的主要提升就是一个连接上向服务器发送多个请求。
    iOS15之后工具也开始支持http3了
    线路阻塞
    使用http1的事务完成图

    使用HTTP/2解决阻塞问题

    使用HTTP/2的事务完成状态

    这是我们改为使用http/2之后的效果,可以看到这里没有明显的阻塞状态了
    我们再次回顾一下 HTTP Transaction by connection 面板,我们可以注意到这里只有一个连接, 这是因为我们不再需要多个连接来发送并发的请求了。这也意味着我们只有一次连接建立的损耗 我们也能注意到可以在事务等待同一个连接的上一个事务的请求响应的时候发送新的请求 我们可以看到请求都在很短时间内发送出去,只剩下等待服务器响应了 我们往下滚动也可以看到,所有的等待都是同时开始的

    实例2

    假如我们APP有一个需要登录的功能,登录之后用户就可以不用登录了


    登录请求过程

    这是之前记录的一个追踪文件 我们可以用工具打开它并分析 左侧是我点击某个按钮时候的任务 第一个任务间隔包含两个事务 最后一个是对应我的第二次put请求


    第一个登录请求
    放大之后我们可以看到,第一个请求得到了一个401的状态码 代表没有访问权限 这是我们预料到的。因为我们没有登录 这个事务被绘制成橙色来表示在http层这不是一个成功的事务 中间绿色的部分表示我们设备的网络空闲了一段时间
    然后我们看第二个事务
    第二个登录请求

    当我们进行操作来登录的时候 我们会重试事务 201响应码表示请求已经被成功处理,并且创建了新的资源 这次成功了 身份验证质询的这种交互 输入密码 然后重试事务 是URL加载系统为我们处理的另外一种case


    两个事务的关系
    所以之前的这两个事务实际上属于同一个任务
    我们来看另外一个事务
    第三个登录请求
    当我正在进行请求的时候 我关闭了app页面 这个任务整体是灰色的,代表被取消 事务的提示label 是橙色 代表又收到了401响应 我们使用一个非常基础的记录系统 第一次的时候用户发送它们的身份验证 一旦服务器验证了用户身份它就会设置一个cookie 这样用户之后的请求就不用身份验证了,我本以为这个任务会发送正确的cookie, 让我们验证一下是否发送了,如前面介绍的 这里应该有一个小的cookie 图标紧邻着HTTP方法 但是这里没有 这意味着没有发送cookie 那么问题来了 是服务器没有给我们提供cookie 还是客户端得到了但没有发送 为了找到原因 我们需要查看之前的事务 并检查我们是否从服务器得到了一个cookie
    失败事务的前置事务
    这是之前的一个事务 也就是登录之后的一个成功请求 可以看到确实有一个cookie图标在响应中, 所以服务器确实返回cookie了 那么我们为什么在下一次中没有发送cookie呢 细节可以查看Transaction列表
    transaction列表
    然后我们查看detail面板
    detail面板

    可以看到我们期望的Set-Cookie Header 第一眼看上去这个cookie很正常但是 细看会发现 它的过期时间是 2020年,在过去 ,所以这会导致URLSession 不发送cookie

    实例3

    有时, 我们的网络资源列表里会一些元素没有正确显示出来


    列表加载的过程

    比如看上面这张图,我们期望找到一个列表加载的过程,所以先选中域名,这里有很多的请求,注意到左下角的detail filter了吗 我们可以在这里过滤


    列表过滤的结果
    选中并放大第一个请求的时间线
    第一个请求

    可以看到一切正常
    但是当我们向后滑动的时候,可以看到一个很短的请求。


    持续时间较短的请求
    继续放大这个请求
    时间线放大后的请求
    可以看到这个请求持续了几毫秒 这不是从服务器拿的请求
    我们再次点击 HTTP Transaction by connection 面板
    HTTP Transaction by connection 面板
    可以看到它并不是执行在一个连接上,而是Local Cache 所以我们知道了我们的请求被缓存了 一个解决办法是告诉服务器设置一个cache-control头部,不缓存这个请求 我们希望每次进入页面都刷新列表,但是不希望在没有改动的时候也加载整个列表。好的方法是我们询问服务器是否有改动,并让服务器告诉客户端。 我们可以更改URLRequest 的cache-policy 如果这样 服务器就会返回304 告诉我们使用本地缓存 如果更改了 就会返回新的数据

    实例4

    如果我们集成了一些SDK,使用时候会发现,集成的SDK在不期望网络操作的时候就发出了网络请求,


    SDK在不期望的时候发出请求

    我们同样可以在detail面板来观察代码哪一部分做了网络请求


    网络请求的详细信息
    从Detail可以看到确实是集成的SDK发出了网络请求
    当我们向下滚动的时候
    SDK的请求的位置信息

    看起来像是 Core Location被激活了 这是非常可疑的,尤其是我并没有用任何操作来触发它。我们可能会想,我的位置是否上传到了服务器,因为CoreLocation和CFNetwork同时存在, 我们可以通过HTTP事务来验证


    detail面板
    从Deatil面板可以看出,这个事务包含了一些标准的头部和我的位置信息, 这非常糟糕,发送这些信息违反了用户的隐私,我们可以使用这个工具生成debug 报告,把它存放在桌面
    生成debug报告
    XCtrace 工具的命令行可以以HTTP归档格式用来报告这个追踪
    XCtrace命令行
    这是一个HTTP流量信息交换的标准,就像图片所示:har 本身是一个JSON格式的,所以也可以在文本编辑器中打开。

    结语

    分享到这里就结束了,希望大家通过简介和实例掌握HTTP Traffic的使用,能够解决遇到的问题,帮助大家的APP越来越好。

    相关文章

      网友评论

          本文标题:Analyze HTTP traffic in Instrume

          本文链接:https://www.haomeiwen.com/subject/xorfpltx.html