WWDC Quick Look 💓 By SwiftGGTeam
Analyze HTTP traffic in Instruments

Analyze HTTP traffic in Instruments

元の動画を見る

ハイライト

Instruments 13 では、HTTP トラフィック インストゥルメントがネットワーク テンプレートに追加され、開発者がプロ​​セス、URLSession、URLSessionTask、HTTP トランザクションごとにアプリの HTTP トラフィックを表示し、同じトレースを使用してパフォーマンスの問題、キャッシュ エラー、認証の問題、プライバシー リスクを特定できるようになります。

主要内容

アプリのネットワークの問題は、多くの場合、コードに直接現れません。

画像の読み込みが遅く、コード内にグループが 1 つしか表示されないURLSessionTask。ユーザーが繰り返しログインすると、コードはサーバーが 401 を返すことだけを示します。お気に入りリストは更新されず、インターフェイスはステータス管理のバグのように見えます。サードパーティの SDK はデータを秘密裏に送信し、ソース コードはプロジェクト内にさえ存在しません。

以前は、これらの問題のトラブルシューティングを行うには、クライアント ログ、サーバー ログ、プロキシ パケット キャプチャ ツールの間で切り替えを行う必要がありました。各ツールは真実の一部しか認識しません。リクエストが送信されたことはわかっていますが、それが誰のものであるかは必ずしもわかりませんURLSession。 HTTP ヘッダーが表示されますが、コードのどの行が呼び出されたのかは必ずしもわかりません。resume()

Apple は、Instruments 13 のネットワーク テンプレートに HTTP トラフィック インストゥルメントを追加しました。これは、Apple ネットワーク スタックに直接接続し、URL ローディング システムを通過する HTTP トラフィックを記録します。 HTTP/3、VPN トラフィック、ディスク キャッシュ ヒット、ネットワーク エラーはすべて同じタイムラインに表示されます。

このトークでは、犬の写真アプリを使用してデモを行います。サーバーは HTTP/1.1 のみをサポートしているため、ホームページの読み込みが遅くなり、同じ接続上のリクエストがキューに入れられます。サーバーが期限切れの Cookie を送り返したため、ログイン ステータスが失われました。リクエストがローカル キャッシュに直接ヒットするため、コレクション リストは更新されません。サードパーティのログイン SDK は、ユーザーがクリックする前に位置座標をアップロードしますが、これはプライバシーの問題です。

主な変更点は、ネットワーク リクエストが単なる URL とステータス コードではなくなったことです。 Instruments は、それを開発者が使い慣れているオブジェクト モデル (プロセス、URLSessionURLSessionTask、トランザクション (HTTP リクエストとレスポンス)。タイムラインから問題を確認でき、バックトレースからソース コードまで遡ることもできます。

詳細

1. オブジェクト レベルで HTTP トラフィックを読み取る

(02:04) HTTP トラフィック計測の一番上のトラックには、トレース内で実行されているものが表示されます。URLSessionTask量。次のレイヤーはプロセスごとに分割され、次のレイヤーはプロセスによって使用されます。URLSession。最下層はリクエストドメイン名ごとに分割されており、タスクとトランザクションのステータスが表示されます。

プロジェクト内に複数のセッションがある場合、デフォルト名をコードに対応させるのは困難です。 Apple は、セッションとタスクにセマンティックな名前を付けることを推奨しています。インストゥルメントはタイムラインにこれ​​らの名前を付けます。

import Foundation

final class FeedLoader {
    private let session: URLSession

    init() {
        let configuration = URLSessionConfiguration.default
        session = URLSession(configuration: configuration)
        session.sessionDescription = "DogFeed Image Loader"
    }

    func loadThumbnail(from url: URL) {
        let task = session.dataTask(with: url) { data, response, error in
            if let error {
                print("thumbnail failed: \(error)")
                return
            }

            print("thumbnail bytes: \(data?.count ?? 0)")
        }

        task.taskDescription = "Load latest dog thumbnail"
        task.resume()
    }
}

キーポイント:

  • URLSessionConfiguration.defaultデフォルトの URLSession 構成を作成します。
  • URLSession(configuration:)独立したセッションを作成します。これは、インストゥルメントのセッション階層に表示されます。
  • session.sessionDescriptionセッションに名前を追加すると、タイムラインとコード オブジェクトを簡単に一致させることができます。
  • session.dataTask(with:)を作成しますURLSessionTask
  • task.taskDescriptionタスクに名前を追加すると、Instruments はその名前を使用してタスク間隔のラベルを付けます。
  • task.resume()リクエストを開始します。講義では、タスク間隔がここで開始され、完了ブロックが呼び出される前に終了することが説明されています。

2. トランザクション ステータスを使用して HTTP/1 行頭ブロックを特定する

(13:18) デモアプリのホームページでは、最初に画像リストをリクエストし、次に各サムネイルを同時にリクエストする必要があります。最初のトレースは、初期画面のロードに 7 秒以上かかることを示しています。後で開始されたサムネイル タスクは遅くなり、紫色のブロック状態がますます長くなります。

にカットHTTP Transactions by Connection見てみると問題が明らかになります。各トランザクションは、独自のリクエストを送信する前に、同じ接続上の前のトランザクションが完了するまで待つ必要があります。これは HTTP/1 の行頭ブロックです。サーバーが HTTP/2 を有効にすると、リクエストを 1 つの接続で多重化できるようになり、合計時間が 3 秒未満に短縮されます。

Instruments
→ Profile with Network template
→ HTTP Traffic
→ Select app process
→ Select server domain
→ Track display: HTTP Transactions by Connection
→ Look for: increasing Blocked state on the same connection
→ Check label: HTTP version

キーポイント:

  • Network templateネットワーク接続計測と HTTP トラフィック計測の両方が含まれます。
  • HTTP Trafficトップレールは、トラフィックのピークを特定するために使用されます。
  • Select server domain特定のバックエンド ドメイン名のリクエストのみを表示できます。
  • HTTP Transactions by Connectionトランザクションは接続ごとにグループ化され、リクエストが同じ接続でキューに入れられているかどうかが判断されます。
  • increasing Blocked stateこれは、このデモンストレーションで先頭の障害物を特定するための直接的な信号です。
  • HTTP versionリクエストがHTTP/1.1、HTTP/2、またはその他のバージョンであることを確認するためにトランザクションラベルに表示されます。

(18:37) ユーザーが初めて写真を収集すると、サーバーは 401 を返します。ユーザーがアカウントのパスワードを入力すると、URL ローディング システムはトランザクションを再試行し、201 を受け取ります。同じ認証チャレンジと再試行プロセスであるため、両方のトランザクションは同じタスクに属します。

2 回目に写真を収集するときに、アプリは再度ログインを要求しました。 Instruments は、リクエストが再び 401 を受信し、リクエスト ラベルに Cookie アイコンがないことを示しています。最後に成功したログインの応答を振り返ると、サーバーは送信しました。Set-Cookie。トランザクションの詳細を展開したところ、Cookie の有効期限が 2020 年 3 月であり、有効期限が切れていることがわかりました。URLSessionそれ以降は発送されません。

HTTP/1.1 201 Created
Set-Cookie: session=abc123; Expires=Wed, 18 Mar 2020 12:00:00 GMT; Path=/; Secure; HttpOnly
Content-Type: application/json

キーポイント:

  • 201 Createdデモでの最初のログイン後の再試行成功のステータス コードに対応します。
  • Set-Cookieサーバーがログイン Cookie を設定しようとしたことを示します。
  • Expires=Wed, 18 Mar 2020 12:00:00 GMTが問題の根源であり、その期限はすでに過ぎていると演説は述べた。
  • Path=/Cookie のパス範囲を制限します。
  • SecureCookie が安全な接続を介してのみ送信されることを示します。
  • HttpOnlyクライアント スクリプトが Cookie を読み取ることができないことを示します。
  • 有効期限が切れたクッキーは保存されません。URLSession送信されたため、次の収集リクエストにはまだ Cookie ヘッダーがありません。

4. キャッシュ戦略を使用して期限切れのリストを修正する

(24:40) コレクションリストには、新しく収集された画像は表示されません。お気に入りリストをロードするタスクは Instruments にありますが、かかる時間は数ミリ秒だけです。にカットHTTP Transactions by Connectionその後、このトランザクションはネットワーク接続上では実行されていないことが判明しました。Local Cache優れた。

これは、リクエストがサーバーに送信されなかったことを意味します。スピーチでの修理方法は、URLRequest設定オンreloadRevalidatingCacheData。このようにして、クライアントはキャッシュがまだ有効であるかどうかをサーバーに確認します。サーバーは 304 を返し、クライアントがローカル キャッシュを引き続き使用できるようにします。データが変更されると、サーバーは新しいデータを返します。

import Foundation

func loadFavorites(from endpoint: URL, session: URLSession = .shared) {
    var request = URLRequest(url: endpoint)
    request.cachePolicy = .reloadRevalidatingCacheData

    let task = session.dataTask(with: request) { data, response, error in
        if let error {
            print("favorites failed: \(error)")
            return
        }

        if let httpResponse = response as? HTTPURLResponse {
            print("status: \(httpResponse.statusCode)")
        }

        print("favorites bytes: \(data?.count ?? 0)")
    }

    task.taskDescription = "Reload favorites with cache revalidation"
    task.resume()
}

キーポイント:

  • URLRequest(url:)お気に入りリストをロードするリクエストを作成します。
  • request.cachePolicyこのリクエストに対してローカル キャッシュがどのように使用されるかを制御します。
  • .reloadRevalidatingCacheDataこれはスピーチで使用されるキャッシュ戦略であり、サーバーに対してキャッシュの有効性を確認します。
  • session.dataTask(with: request)キャッシュ ポリシーを使用したリクエストを使用してタスクを作成します。
  • HTTPURLResponse.statusCodeサーバーから返されたステータス コードを出力できます。サーバーが利用可能であるという話 304 は、キャッシュがまだ有効であることを意味します。
  • task.taskDescriptionインストゥルメントのタスクを識別しやすくします。
  • task.resume()リクエストをしてください。

5. バックトレースと HAR を使用してサードパーティ SDK をエクスポートおよび監査する

(29:19) 講演は、サードパーティのログイン SDK を調べることで終了します。アプリはログイン ページに入ったばかりで、まだ SDK のログイン ボタンをクリックしていません。楽器はすでに表示されています。Pets Sign On Networkセッションがリクエストを送信しています。リクエストは POST であり、バックトレースは、リクエストが SDK からのものであり、CoreLocation に関係していることを示しています。

トランザクションの詳細を展開した後、リクエスト本文には位置座標が含まれます。この演説では、こうした行為がユーザーのプライバシーを侵害することを明確にした。開発者はトレースを保存して使用できます。xctraceHTTP アーカイブ (HAR) ファイルをエクスポートし、SDK チームに送信して問題を再現します。

xcrun xctrace export \
  --input ~/Desktop/PrivacyViolation.trace \
  --har \
  --output ~/Desktop/PrivacyViolation.har

キーポイント:

  • xcrunXcode に含まれるコマンド ライン ツールを呼び出します。
  • xctrace exportInstruments トレースからデータをエクスポートします。
  • --input ~/Desktop/PrivacyViolation.trace講義内に保存したトレースファイルを指定します。
  • --harHTTP トラフィック情報を交換するための HTTP アーカイブ形式を選択します。
  • HAR は、HAR 対応ツール、テキスト エディター、またはスクリプトを使用して検査できる JSON ベースの形式です。
  • プレゼンテーションノート HAR には、機器の専有情報は含まれません。URLSessionバックトレースですが、相手が HTTP コンテンツを調査できるようにするには十分です。

重要ポイント

1. ネットワーク層に監視可能な名前を追加します。

  • やるべきこと: ビジネス シナリオごとにURLSessionそして鍵URLSessionTask画像の読み込み、ログイン、コレクションの同期などの設定の説明。
  • 実行する価値がある理由: HTTP Traffic Instrument は、sessionDescriptionそしてtaskDescriptionタイムライン上に表示されるため、トラブルシューティング時にURLから業務の意味を推測する必要がありません。
  • 開始方法: ネットワークカプセル化での初期化URLSession投稿設定session.sessionDescription、タスクの作成後に設定しますtask.taskDescription次に、ネットワーク テンプレートを使用してコア プロセスを記録します。

2. 最初の画面のネットワーク パフォーマンス検査プロセスを作成する

  • 何をすべきか: ホーム ページのインターフェイスまたは画像の読み込み戦略を変更した後は、毎回、インストルメントを使用して、最初の画面リクエストが長時間ブロック状態で表示されるかどうかを確認します。
  • 実行する価値がある理由: スピーチの最初のページが 7 秒以上から 3 秒未満に短縮されました。核心的な手がかりは、HTTP Transactions by Connection列の先頭がブロックされています。
  • 開始方法: アプリの起動後に完了したトレースを最初の画面に記録し、ドメイン名で HTTP トラフィックを展開し、に切り替えます。HTTP Transactions by Connection、HTTP バージョンとブロック状態を確認します。
  • 対処方法: ログイン、再試行、保護されたリソースの再リクエストのリンクをトレースとして記録し、サーバーが有効な Cookie を設定したかどうか、および後続のリクエストに Cookie ヘッダーが含まれているかどうかを確認します。
  • 実行する価値がある理由: 音声のバグはクライアントの保存ロジックではなく、有効期限を返すサーバーにあります。Set-Cookie
  • 開始方法: トランザクションの詳細で応答ヘッダーを表示しますSet-Cookieを確認し、次のリクエストラベルまたはリクエストヘッダーにCookieが含まれているかどうかを確認します。

4. キャッシュ レビューを変更リストに追加します

  • 対処方法: お気に入りリスト、通知リスト、コラボレーション データなど、変更されるデータに対して必要に応じてキャッシュ レビュー戦略を使用します。
  • 実行する価値がある理由: スピーチでヒットしたお気に入りリストLocal Cacheそのため、ユーザーには新しいコレクションが表示されなくなります。reloadRevalidatingCacheDataクライアントがキャッシュの有効期限が切れているかどうかをサーバーに確認できるようにします。
  • 開始方法: 通信を見つけますURLRequest、設定request.cachePolicy = .reloadRevalidatingCacheData、次に Instruments を使用して、トランザクションが接続に到達したか、または 304 を受信したかを確認します。

5. サードパーティ SDK を接続する前にプライバシー チェックを自動化する

  • 対処方法: SDK を統合した後、アプリのコールド スタート前後の HTTP トラフィックを記録し、ログイン ページにアクセスして SDK ボタンをクリックし、予期しないリクエスト ボディ、位置データ、または認証情報が存在するかどうかを確認します。
  • 実行する価値がある理由: HTTP Traffic Instrument は、SDK 自体によって作成されたセッション、POST リクエスト、ヘッダー、本文、およびバックトレースを表示できます。
  • 開始方法: ネットワーク テンプレートを使用してトレースを記録し、SDK セッションを選択し、トランザクションの詳細を表示します。使用xcrun xctrace export --harバグレポートに添付された HAR をエクスポートします。

関連セッション

コメント

GitHub Issues · utterances