# ネットワークリクエストとレスポンスを変更する: chrome-use network route 詳解

{開発|かいはつ}していると、ネットワークを{一時的|いちじてき}に少し{変|か}えたくなる{瞬間|しゅんかん}がどうしてもあります。バックエンドAPIがまだできていないので、まず{仮|かり}データでフロントエンドを{動|うご}かしたい。あるリクエストに{別|べつ}のパラメータを{付|つ}けたらどうなるか{試|ため}したい。あるいは{統計|とうけい}や{埋|う}め{込|こ}み{計測|けいそく}のリクエストをそのまま{止|と}めたい。これまでは、コードを{変更|へんこう}してスイッチを{追加|ついか}するか、mock serverを{立|た}てるか、パケットキャプチャ用のプロキシを{挟|はさ}むか（しかもCA{証明書|しょうめいしょ}のインストールが{必要|ひつよう}）でした。どれも極端に{重|おも}いわけではありませんが、どれも{追加|ついか}の{準備|じゅんび}が{必要|ひつよう}です。

chrome-useの `network route` は、この{作業|さぎょう}をブラウザ{本体|ほんたい}の{中|なか}に{収|おさ}めます。あなたが{操作|そうさ}しているそのChrome上で、マッチしたリクエストを{直接|ちょくせつ}インターセプトし、レスポンスをmockする、{送信|そうしん}されるリクエストを{変更|へんこう}する、またはそのままブロックできます。プロキシも{証明書|しょうめいしょ}も、{検証|けんしょう}{対象|たいしょう}コードの{変更|へんこう}も{不要|ふよう}です。

![リクエストがインターセプト地点に当たった後、一方はmockの仮データを直接返し、もう一方は変更済みのリクエストヘッダーを付けてサーバーへ流す](https://img.leeguoo.com/media/a921299c-f3a4-4452-bb56-214f95fe6bd2/chrome-use-network-cover.png)

## 4つの{使|つか}い{方|かた}

1つの `network route` コマンドが、{渡|わた}したパラメータに{応|おう}じて{動作|どうさ}を{決|き}めます。

```bash
# 1) Mockレスポンス: リクエストは外へ送られず、指定した仮データを直接返す
chrome-use network route "*/api/me" --body '{"vip":true}' --status 200 --content-type application/json

# 2) リクエスト変更: リクエストは送るが、メソッド/ヘッダー/ボディ/URLを変更し、実レスポンスは通常どおり返る
chrome-use network route "*/api/save" --method POST --set-header Authorization="Bearer test"
chrome-use network route "*/v1/*" --rewrite-url https://staging.example.com/v1/thing

# 3) 実レスポンス変更: リクエストは送信し、実レスポンス取得後にステータス/ヘッダー/ボディを変更する
chrome-use network route "*/api/me" --edit-status 503 --edit-header X-Env=test --replace 'prod=>staging'

# 4) ブロック: 直接止める（埋め込み計測の遮断、オフラインテスト）
chrome-use network route "*/analytics" --abort
```

{区別|くべつ}はとても{簡単|かんたん}です。mock{用|よう}フィールド（`--body` / `--status` / `--header` / `--content-type`）があればレスポンスを{偽造|ぎぞう}し、リクエストは{短絡|たんらく}されて{外|そと}へ{出|で}ません。リクエスト{用|よう}フィールド（`--method` / `--set-body` / `--set-header` / `--rewrite-url`）があれば、{変更|へんこう}してから{通過|つうか}させ、{実際|じっさい}のレスポンスを{受|う}け{取|と}ります。{編集|へんしゅう}{用|よう}フィールド（`--edit-status` / `--edit-header` / `--replace 'from=>to'`）があれば、まず{通過|つうか}させ、{実|じつ}レスポンスが{戻|もど}ってきてからそれを{変更|へんこう}します。mockと「{実|じつ}レスポンス{変更|へんこう}」の{違|ちが}いはここにあります。{前者|ぜんしゃ}はまったく{外|そと}へ{出|で}ず、データを{自分|じぶん}で{作|つく}ります。{後者|こうしゃ}は{実|じつ}レスポンスが{返|かえ}ってくる{必要|ひつよう}があり、その{一部|いちぶ}だけを{変更|へんこう}します。これらのヘッダー{関連|かんれん}パラメータはいずれも{複数回|ふくすうかい}{指定|してい}でき、{既存|きそん}ヘッダーにマージして{上書|うわが}きします。

{名前|なまえ}は{意図的|いとてき}にPlaywrightの `route` / `fulfill` / `continue` / `abort` に{合|あ}わせています。{使|つか}ったことがある{人|ひと}なら{学|まな}び{直|なお}す{必要|ひつよう}はありません。

## {原理|げんり}: すでに{話|はな}しているプロトコル

この{仕組|しく}みの{内部|ないぶ}はChrome DevTools ProtocolのFetchドメインです。`Fetch.enable` でマッチルールを{設定|せってい}し、ヒットしたリクエストは `Fetch.requestPaused` で{停止|ていし}します。その後、{状況|じょうきょう}に{応|おう}じて `fulfillRequest`（{仮|かり}レスポンスを{返|かえ}す）、`continueRequest`（{上書|うわが}きパラメータつきで{通過|つうか}させる）、または `failRequest`（ブロック）を{呼|よ}びます。これは{新|あたら}しく{作|つく}った{仕組|しく}みではありません。DevToolsの「Local Overrides」やPlaywrightのrouteも、Chromeに{対|たい}するインターセプトの{内部|ないぶ}では、{同|おな}じFetchドメインを{包|つつ}んでいます。

![リクエストがrequestPausedで停止した後の3つの行き先: fulfillで仮レスポンスを返す、continueで変更を持たせてサーバーへ流す、abortで直接ブロックする。すべてchrome.debuggerのCDP Fetch経路を通る](https://img.leeguoo.com/media/3f1393f6-cca5-4fde-9b45-e78963110901/chrome-use-network-principle.png)

chrome-useにとって、{重要|じゅうよう}な{点|てん}は2つあります。

1つ{目|め}は、もともとCDPを{話|はな}していることです。chrome-useは{独自|どくじ}のネイティブCDPクライアントでブラウザを{操作|そうさ}しており、`fulfillRequest` / `continueRequest` などのコマンドはすでにコード{内|ない}にあります（ドメインフィルタやプロキシ{認証|にんしょう}でも{使|つか}っています）。mockやリクエスト{変更|へんこう}の{追加|ついか}は、{既存|きそん}の{実行|じっこう}{能力|のうりょく}をコマンドラインから{出|だ}しただけに{近|ちか}く、ゼロから{別|べつ}の{仕組|しく}みを{書|か}いたわけではありません。

2つ{目|め}は、ブラウザ{拡張機能|かくちょうきのう}の{権限|けんげん}に{触|ふ}れないことです。chrome-useが{実際|じっさい}のChromeにつながるときは、{拡張機能|かくちょうきのう}の `chrome.debugger` {経路|けいろ}を{使|つか}います。リクエストのインターセプトは、この{経路|けいろ}でCDPコマンドをいくつか{追加|ついか}で{送|おく}るだけです。{拡張機能|かくちょうきのう}のmanifestは1{文字|もじ}も{変|か}える{必要|ひつよう}がなく、`webRequest` も{不要|ふよう}で、`declarativeNetRequest` も{不要|ふよう}です。そしてこの2つは、まさにChromeウェブストアが{重点的|じゅうてんてき}に{審査|しんさ}する{権限|けんげん}です。つまり、この{機能|きのう}は{新|あたら}しい{権限|けんげん}を{一切|いっさい}{導入|どうにゅう}せず、{拡張機能|かくちょうきのう}の{審査|しんさ}{通過|つうか}に{悪影響|あくえいきょう}を{与|あた}えるリスクもありません。

ついでに、なぜ{既存|きそん}のmockツールをそのまま{統合|とうごう}しなかったのかも{説明|せつめい}します。いくつか{調査|ちょうさ}しました。mockttpはプロセス{内|ない}のNodeプロキシで、{自己署名|じこしょめい}CAが{必要|ひつよう}です。mitmproxyは{独立|どくりつ}したPython MITMプロキシで、こちらも{証明書|しょうめいしょ}のインストールが{必要|ひつよう}です。MSWはページにService Workerを{注入|ちゅうにゅう}するため、この{道|みち}はchrome-useの「JS{注入|ちゅうにゅう}ゼロ」というステルス{原則|げんそく}に{直接|ちょくせつ}{反|はん}します。これらは{重|おも}いか、プロキシと{証明書|しょうめいしょ}が{必要|ひつよう}か、ステルス{性|せい}を{壊|こわ}すかのどれかです。そしてChromeに{対|たい}するインターセプトでは、{内部|ないぶ}でやはりCDP Fetchを{包|つつ}んでいます。すでにこのプロトコルを{話|はな}しているなら、{表面|ひょうめん}を{補|おぎな}うのが{最|もっと}も{軽|かる}い{道|みち}です。

## {実機|じっき}で{一度|いちど}{動|うご}かす

[httpbin.org](https://httpbin.org)（リクエストをそのままエコーバックしてくれる）を{使|つか}って、2つの{主|おも}な{経路|けいろ}を{検証|けんしょう}します。まず{隔離|かくり}したブラウザを{起動|きどう}します。

Mockレスポンス: `/get` に{仮|かり}データを{設定|せってい}し、その後ページ{内|ない}からfetchします。

```bash
chrome-use --launch --session demo network route "*/get" \
  --body '{"mocked":true,"by":"chrome-use"}' --status 200 --content-type application/json
chrome-use --session demo open https://httpbin.org/
# ページ内: fetch('/get') → {"mocked":true,"by":"chrome-use"}
```

{返|かえ}ってくるのは{設定|せってい}した{仮|かり}データであり、httpbinの{実際|じっさい}の `/get` レスポンスではありません。リクエストはまったく{外|そと}へ{出|で}ていません。

リクエスト{変更|へんこう}: `/headers` にカスタムヘッダーを{追加|ついか}し、もう{一度|いちど}fetchします（httpbinは{受|う}け{取|と}ったリクエストヘッダーをエコーバックします）。

```bash
chrome-use --session demo network route "*/headers" --set-header X-Chrome-Use=hello123
# ページ内: fetch('/headers') → エコーされたheaders内に "X-Chrome-Use": "hello123" が現れる
```

httpbinがエコーバックしたリクエストヘッダーに `X-Chrome-Use: hello123` が{含|ふく}まれているため、このヘッダーがリクエストの{実際|じっさい}の{送信前|そうしんまえ}に{追加|ついか}されたことがわかります。

{実|じつ}レスポンス{変更|へんこう}は [example.com](https://example.com) で{検証|けんしょう}します。リクエストは{通常|つうじょう}どおり{送信|そうしん}し、{実際|じっさい}のページを{取得|しゅとく}した後、レスポンスボディ{内|ない}の{文字列|もじれつ}を{置換|ちかん}し、ステータスコードを599に{変更|へんこう}し、レスポンスヘッダーを{追加|ついか}します。

```bash
chrome-use --launch --session demo network route "*example.com/" \
  --edit-status 599 --edit-header X-Edited=yes --replace 'Example=>EDITED' --resource-type xhr,fetch
chrome-use --session demo open https://example.com/
# ページ内で fetch('/') → {status:599, xedited:"yes", bodyEdited:true}
```

{取得|しゅとく}できるのは、{実|じつ}レスポンスを{変更|へんこう}したバージョンです。ステータスコードは599になり、`X-Edited` ヘッダーが{追加|ついか}され、ボディ{内|ない}の `Example` は `EDITED` に{置|お}き{換|か}わっています。ここでは `--resource-type xhr,fetch` を{使|つか}い、{編集|へんしゅう}{対象|たいしょう}をAPIリクエストに{限定|げんてい}し、トップレベルドキュメントのナビゲーションには{触|ふ}れないようにしています（ナビゲーションドキュメントのステータスコードをエラーコードに{変|か}えると、ページ{読|よ}み{込|こ}みの{意味|いみ}が{乱|みだ}れるためです）。

## {現在|げんざい}の{境界|きょうかい}

{実|じつ}レスポンス{変更|へんこう}は、{現時点|げんじてん}では「レスポンスボディ{全体|ぜんたい}を{取得|しゅとく}し、{文字列|もじれつ}{置換|ちかん} + ステータス/ヘッダーの{上書|うわが}き」をするものです。{日常的|にちじょうてき}にフィールドを{変|か}えたり、エラー{状態|じょうたい}を{作|つく}ったりするには{十分|じゅうぶん}です。より{細|こま}かい{構造化|こうぞうか}{書|か}き{換|か}え（たとえばJSONのあるフィールドだけを{変|か}えるなど）は、{今|いま}は{文字列|もじれつ}{置換|ちかん}で{対応|たいおう}します。{今後|こんご}、{需要|じゅよう}を{見|み}て{考|かんが}えます。また、もともとHARは{記録|きろく}できるので、{次|つぎ}のステップとして、{記録|きろく}したHARエントリをそのままmock fixtureとして{使|つか}えるようにする{予定|よてい}です。{一度|いちど}{記録|きろく}し、{再生時|さいせいじ}に少し{変更|へんこう}すればよい、という{形|かたち}です。

2つのリポジトリがあります。chrome-useは [github.com/leeguooooo/chrome-use](https://github.com/leeguooooo/chrome-use) にあります。{完全|かんぜん}なコマンドは `chrome-use skills get core` でローカルに{取得|しゅとく}して{確認|かくにん}できます。

関連ドキュメント（英語）：[chrome-use · Network Interception](https://chrome-use.leeguoo.com/en/network.html)、[インストール](https://chrome-use.leeguoo.com/en/install.html)。
