Fiddler は、ブラウザーとサーバーのあいだに入って通信を記録・変更できる、デバッグ用のプロキシ (通信を中継するソフト) です。その AutoResponder という機能を使うと、特定の URL への要求に、サーバーの代わりに手元のファイルを返せます。公開中のサイトの JavaScript を、手元で直したファイルに差し替えて試す、といった使い方ができます。ところが、ルールを正規表現で書いたとき、URL にクエリ (?v=123 のような部分) が付いていると一致せず、差し替わらないことがあります。
Fiddler には、Windows 向けの Fiddler Classic と、あとから出た Fiddler Everywhere があり、画面や機能の名前が違います。ここでは Fiddler Classic の AutoResponder を例に説明します。細かな動きは版によって違うことがあるので、使っている版の説明もあわせて確かめてください。
ルールの書き方による違い
AutoResponder のルールは、「どの URL に一致したら」と「何を返すか」の組です。公式の資料によると、一致の条件は書き方によって次のように扱われます。
- 文字列だけを書く (
example.com/js/app.js): URL のどこかにその文字列が含まれていれば一致します。大文字と小文字は区別しません EXACT:を付ける: URL 全体が完全に同じときだけ一致します。大文字と小文字を区別しますREGEX:を付ける: 正規表現で判定します。資料の例では、大文字と小文字を区別しています
資料の例では、スキーム (https://) からクエリまでを含む URL 全体と照らし合わせています。そのため、EXACT: のルールは、クエリが付いた URL には一致しません。
REGEX: のルールが一致しない原因
$ で終わりを固定している
REGEX:^https://example\.com/js/app\.js$
^ は文字列の先頭、$ は末尾を表します。ブラウザーが要求する URL が https://example.com/js/app.js?v=123 だと、app.js のあとに ?v=123 が続くので、$ の位置で一致しません。キャッシュを避けるために、読み込むファイルの URL にクエリを付けているサイトは多いので、よく起きます。
? や . をエスケープしていない
正規表現では、? は「直前の文字が 0 回か 1 回」、. は「任意の 1 文字」という意味です。URL をそのまま貼り付けて、次のように書くと、? が文字として扱われません。
REGEX:https://example.com/js/app.js?v=123
この正規表現の js? は「j のあとに s があってもなくてもよい」という意味になり、URL の中の ? という文字には一致しません。そのため、app.js?v=123 という URL に一致しなくなります。文字としての ? や . は、\?、\. のように \ を付けて書きます。. はエスケープしなくても「任意の 1 文字」として一致してしまうので気づきにくいのですが、意図しない URL にまで一致する原因になります。
大文字と小文字が違う
URL に大文字が混じっていると、小文字で書いたルールに一致しないことがあります。区別したくないときは、REGEX:(?i)^https://... のように、正規表現の先頭に (?i) を付けます。
クエリがあってもなくても一致させる
REGEX:^https://example\.com/js/app\.js(\?.*)?$
(\?.*)? は、「? から始まる部分が、あってもなくてもよい」という意味です。これで、app.js にも app.js?v=123 にも一致し、app.json や app.js.map には一致しません。
フォルダーの中の .js をまとめて差し替えたいときは、パスの部分に .* ではなく、「? 以外の文字の並び」を表す [^?]* を使うと、範囲を絞れます。
REGEX:^https://example\.com/js/[^?]*\.js(\?.*)?$
.* で書くと、https://example.com/js/load.php?file=a.js のように、クエリの中に .js がある URL にも一致してしまいます。
なお、.* は「できるだけ長く」一致させ (最長一致)、.*? は「できるだけ短く」一致させます (最短一致)。一致するかどうかだけを判定する場面では、この違いで結果が変わることはあまりありません。違いが出るのは、一致した部分のどこまでを取り出すかが問題になるときです。一致しない原因を探すときは、まず $ とエスケープを疑いましょう。
一致するかを確かめる
ルールを直したら、実際の URL で一致を確かめます。Fiddler の通信の一覧から、対象の要求の URL をコピーしておくと確実です。
Fiddler Classic は .NET で作られていて、正規表現も .NET のものです。同じ .NET の正規表現を使う PowerShell で試すと、手軽に確かめられます。
$pattern = '^https://example\.com/js/app\.js(\?.*)?$'
[regex]::IsMatch('https://example.com/js/app.js?v=123', $pattern) # True
[regex]::IsMatch('https://example.com/js/app.json', $pattern) # False
正規表現が正しいのに差し替わらないときは、次の点も見直します。
- HTTPS の通信を復号する設定 (Decrypt HTTPS traffic) が有効か。無効だと HTTPS の要求の中身が見えないため、URL によるルールが働きません
- ブラウザーのキャッシュから読み込まれていないか。要求そのものが送られないと、ルールは働きません。開発者ツールでキャッシュを無効にして読み込み直します
- 目的のルールが有効になっているか。より上にある別のルールが、先に一致していないか
- 一致しなかった要求を本来のサーバーへ通す設定 (Unmatched requests passthrough) が外れていないか。外れていると、ルールに一致しなかった要求がサーバーに届かず、ページの一部がエラーになることがあります
開発者ツールのオーバーライドでもできる
手元のファイルに差し替えるだけなら、今はブラウザーの開発者ツールでもできます。Chrome の開発者ツールの「ローカルでのオーバーライド (Local overrides)」では、Network パネルで要求を右クリックし、「Override content」を選びます。保存先のフォルダーを選ぶと、応答の内容を手元で書き換えられ、ページを読み込み直しても、書き換えた内容が使われます。応答のヘッダーを変えることもできます。
正規表現で多くの URL をまとめて差し替えたい、ブラウザー以外のアプリの通信も扱いたい、といった場合は、Fiddler のようなプロキシが向いています。目的に合わせて使い分けましょう。正規表現の書き方は、正規表現のタグ の記事も参考にしてください。
まとめ
REGEX:のルールの末尾に$を付けると、クエリ付きの URL に一致しない。(\?.*)?$でクエリを許す- URL の
?や.は、正規表現では\?、\.とエスケープする - 大文字と小文字を区別したくないときは
(?i)を付ける - 一致は PowerShell の
[regex]::IsMatch()などで確かめ、HTTPS の復号やキャッシュも見直す - 手元のファイルに差し替えるだけなら、ブラウザーの開発者ツールのオーバーライドも使える