メインコンテンツまでスキップ

Scripting

Proxyman の Scripting ツールを使い、JavaScript で HTTP リクエストとレスポンスを変更したり、モック API を作成したり、onWebsocket で WebSocket メッセージをログに記録したりできます。

1. 概要​

Proxyman には Scripting ツールがあります。JavaScript コードを書くことで、リクエストとレスポンスを柔軟に変更できます。

2. メリット​

  • JS コードを使って Map Local / Map Remote / Breakpoint を実装できます。100 倍高速
  • リクエストの内容を変更できます。対象は Domain、Host、Scheme、Port、Path、HTTP Method、HTTP Headers、Query、Body(Encoded-Form、JSON、plain-text)です。
  • onWebsocket で WebSocket メッセージをログに記録し、確認できます(macOS、Windows、Linux 版 Proxyman 26.1.0 以降)。
  • onWebsocket で WebSocket メッセージの編集、ドロップ、送信ができます(macOS 版 Proxyman 26.2.0 以降、Windows/Linux 版 Proxyman 26.1.0 以降)。
  • レスポンスの内容を変更できます。対象は HTTP Status Code、HTTP Headers、Body(JSON、Encoded-Form、plain-text、binary...)です。
  • 組み込みのアドオンとライブラリが豊富にあり、Hashing、Encode/Decode、JSON-Text transformer、Beautify などの一般的な処理に使えます。
  • 独自の JS アドオンやライブラリを作成できます
  • Charles Proxy の Rewrite GUI Tool を置き換えるために設計されています。
  • Shared State または Environment Variables を使うと、現在のセッション内のスクリプト間で状態を共有できます。
POST ルール、Request と Response のチェック、Run as Mock API、onRequest と onResponse のコードを表示した Proxyman Script Editor

Scripting ツール

3. 使い方​

次の方法で Scripting ツールを開けます:

  • Scripting メニュー → Script List…(⌥⌘I)
  • フローを右クリック → Tools → Scripting…

Scripting ツール向けの JS スニペットをまとめた スニペットコード ページもご覧ください。

4. GraphQL リクエストでの Scripting​

Proxyman 2.27.0 以降では、Scripting ツールは QueryName を使って GraphQL リクエストをマッチさせられます。次の GraphQL のドキュメントもご覧ください。

4.1 WebSocket での Scripting​

macOS 版 Proxyman 6.2.0 以降では、onRequest と onResponse を使って WebSocket のリクエスト URL とハンドシェイクのヘッダーを変更できます。WebSocket の URL とヘッダーを変更する を参照してください。

onWebsocket でメッセージをログに記録​

警告

onWebsocket は macOS、Windows、Linux 版 Proxyman 26.1.0 以降で利用できます。iOS では利用できません。

onWebsocket(context, url, request, response, message) を使うと、クライアントとサーバーの両方からキャプチャしたメッセージを確認し、ログに記録できます:

function onWebsocket(context, url, request, response, message) {
console.log(`[${message.from}] ${message.type}: ${message.data}`);
}

デフォルトでは、このフックは読み取り専用です。Proxyman はスクリプトを実行する前にメッセージを転送します。引数を変更したり値を返したりしても、通信やキャプチャされたメッセージは変更されません。return 文は不要です。

メッセージを編集、ドロップ、送信するには、ルールで Modify WebSocket Messages にチェックを入れます(macOS 版 Proxyman 26.2.0 以降、Windows/Linux 版 Proxyman 26.1.0 以降)。詳しくは Modify WebSocket Messages を参照してください。

使い方

  1. WebSocket 接続をキャプチャします。wss:// の場合は、Proxyman がメッセージを読み取れるように、そのホストで SSL Proxying を有効にしてください。
  2. キャプチャしたフローを右クリックし、Tools → Scripting を選択します。生成されたスクリプトには、onResponse の下に onWebsocket が含まれています。
  3. ログ出力のコードを追加し、Save & Activate をクリックします。
  4. WebSocket に再接続し、メッセージを送信して、スクリプトの Console Log を確認します。

接続を開いたときにルールが有効になっている必要があります。ルールを作成した後や、接続を開いた時点で onWebsocket が含まれていなかったスクリプトに onWebsocket を追加した後は、再接続してください。通常の新規スクリプトのテンプレートにはこのフックは含まれていないため、手動で追加できます。

引数

引数は 5 つすべてを、この順番どおりに指定してください。context と url は、フローと一致したルールを表します。request と response には、onRequest、onResponse、Breakpoint による変更を含む、最終的なハンドシェイクが入ります。message には次の情報が含まれます:

フィールド値
message.type"text"、"binary"、"ping"、"pong"、または "close" です。
message.from"client" または "server" です。
message.data常に文字列です。バイナリデータは可能な場合 UTF-8 テキストとして表示され、それ以外の場合は Binary (length=N) と表示されます。WebSocket タブのオプションのデコーダーは適用されません。
message.rawDataコピーされた Uint8Array で、バイナリメッセージでのみ利用できます。明示的にログ出力してください。message を列挙しても含まれません。
message.closeCode数値で、close メッセージでのみ利用できます(例:1000)。

注意事項

  • 分割されたテキストフレームとバイナリフレームは、フックを実行する前に再構成されます。継続フレームごとに個別のコールバックが呼ばれるのではなく、完全な 1 つのメッセージを受け取ります。
  • Ping/pong のペイロードと close の理由は公開されません。
  • 同期フックと async フックに対応しています。console.log、require、sharedState、$http などのヘルパーも利用できます。
  • 既存のフックの編集や、ルール、フォルダ、ツールの有効化状態は、メッセージが届くたびに最大で 1 秒に 1 回確認されます。キューに入っている呼び出しは完了することがあります。
  • Console Log には最新の 200 件のログエントリが保持されます。スクリプトの処理が追いつかない場合、通信は続く一方でフックの呼び出しが警告付きでスキップされることがあります。Console Log はデバッグ用であり、通信の完全なアーカイブとしては使えません。

テキスト、JSON、バイナリ、ping/pong、close の例については、WebSocket メッセージのスニペット を参照してください。

5. 例​

次のガイドでは、JS コードでリクエストのドメインを本番環境から localhost に変更し、レスポンスのボディを変更する方法を説明します。

  1. スクリプトを作成する前に、このドメインで SSL Proxying を有効にしてください。
  2. Scripting ツールを開き、新しい Script Entry を作成します(⌘N)。リクエストを右クリックして Tools → Scripting… を選択することもできます。すると、Proxyman がスクリプトを作成します。
  3. 名前を付けて、Matching Rule を定義します。
  4. 例:Name=Test on Localhost endpoint、URL=https://proxyman.io
  5. Run Script on で Request と Response のチェックボックスをオンにします。
  6. onRequest 関数の JS コードを書き始めます。

onRequest(context, url, request) {}

// Import UUID addons
const { uuidv4 } = require("@addons/UUID.js");

function onRequest(context, url, request) {
// print log
console.log(request);

// Change Production domain -> Localhost
request.method = "GET";
request.scheme = "http";
request.host = "localhost";
request.port = 8000;

// Add new header
request.headers["X-New-Header"] = "Hello From Scripting feature";
request.headers["UUID"] = uuidv4(); // generate random UUIDv4
delete request.headers["Key-Need-Delete"];

// Update or Add a new Query
request.queries["name"] = "Proxyman";

// Update Body
var body = request.body;
body["name"] = "Proxyman";
request.body = body;

// Or Map the body with a local file (Proxyman 2.25.0+)
// request.bodyFilePath = "~/Desktop/mockdata.json";

// Done
return request;
}

onRequest() オブジェクトの形式​

context、url、request オブジェクトは次のように定義されます:

// context (readonly)
{
"scriptName": "<String> Your Script Name",
"matchingRule": "<String> Your Matching Rule",
"matchingMethod": "<String> Method",
"isEnableOnRequest": "Bool",
"isEnableOnResponse": "Bool",
"filePath": "<String> Script path",
"flow": { // Available from 2.16.0+
"serverPort": "443",
"serverIpAddress": "104.18.230.83",
"clientIpAddress": "192.168.0.102",
"remoteDeviceName": "iPhone XR",
"remoteDeviceIP": "192.168.0.102",
"id": "51",
"clientPath": null,
"clientPort": "51494",
"clientName": null,
"mapRemoteOriginalURL": "<String> Original URL before Map Remote modification (nullable)"
},
}

// url (readonly)
url: String // => Present the full URL

// request
{
"method": "<String> HTTP Method. Accept string method. Ex: GET, POST, ...",
"scheme": "<String> Accept http or https",
"host": "<String> Host of the request. Ex: api.proxyman.io, localhost, ...",
"path": "<String>: Path of the URL. Ex: /v1/data",
"port": "<Int> Accept int port number. Ex: 443, 8080, ..",
"queries": "<[String: Any]> A JS Object (Dictionary) contains key values of the query",
"headers": "<[String: Any]> A JS Object (Dictionary) contains key values of the header",
"body": "Depend on the Content-Type header. It might be a dictionary for JSON and form, Plain Text or Uint8Array",
"bodyFilePath": "<String><Optional> Set a body with a local file. See example in Snippet Code Page"
"rawBody": "<Readonly>: A raw body String or Uint8Array",
"preserveHostHeader": "<Bool> Preserve the Host",
"isURLEncoding": "<Bool> Determine if Proxyman will perform URLEncoding when constructing the final URL. Default is True",
"upstream": "<Object><Optional> Upstream TLS ALPN and HTTP/2 settings. Proxyman v26.0.0 or later for macOS."
}

備考

rawBody を除く、request オブジェクトのすべての値を変更できます。

onRequest で request.upstream を設定します。例と対応しているフィールドについては、Upstream ALPN と HTTP/2 の設定 を参照してください。

備考

Content-Type ヘッダーが正しくないために body の形式が不正になる場合は、rawBody を使い、文字列を手動で解析してください。

request.body の型は Content-Type ヘッダーによって決まります。

Content-Type ヘッダーrequest.body
application/json または JSON 系Javascript Object
application/x-www-form-urlencodedJavascript Object
plain-text またはテキストベースの Content-Type(例:application/js、text/css、text/html など)String
それ以外:バイナリデータ(application/zip、application/octet-stream)Uint8Array

よく使う JS コードは、スニペットコードのページにまとめています:

7. onResponse 関数でコードを書き始めます

function onResponse(context, url, request, response) {
console.log(response);

// Update or Add a new header
response.headers["Content-Type"] = "application/json";

// Update status Code
response.statusCode = 500;

// Update Body
var body = response.body;
body["new-key"] = "Proxyman";
response.body = body;

// Or Map the body with a local file (Proxyman 2.25.0+)
// response.bodyFilePath = "~/Desktop/mockdata.json";

// Done
return response;
}

onResponse() オブジェクトの形式​

context、url、request、response オブジェクトは次のように定義されます:

// context (readonly): Same with onRequest

// url (readonly): Same with onRequest

// request (readonly): Same with onRequest

// response
{
"statusCode": "<Int> Status Code. Ex: 200, 400, 404,...",
"httpVersion": "<String><Readonly> The HTTP Version",
"statusPhrase": "<String><Readonly> HTTP Status Phrase. Ex Not Found, OK, ...",
"headers": "<[String: Any]> A JS Object (Dictionary) contains key values of the header",
"body": "Depend on the Content-Type header. It might be a dictionary for JSON and form, PlainText or Uint8Array",
"rawBody": "<Readonly>: A raw body String or Uint8Array",
"bodyFilePath": "<String><Optional> Set a body with a local file. See example in Snippet Code Page"
}
備考

response オブジェクトの statusCode、headers、body を変更できます。

備考

Content-Type ヘッダーが正しくないために body の形式が不正になる場合は、rawBody を使い、文字列を手動で解析してください。

response.body の型は Content-Type ヘッダーによって決まります。

Content-Type ヘッダーresponse.body
application/json または JSON 系Javascript Object
application/x-www-form-urlencodedJavascript Object
plain-text またはテキストベースの Content-Type(例:application/js、text/css、text/html など)String
それ以外(application/zip、application/octet-stream)Uint8Array
備考

onRequest と onResponse 関数では、request と response オブジェクトを必ず return してください。

6. 組み込みのアドオンとライブラリ​

Proxyman には、一般的な処理向けのアドオンとライブラリが豊富に用意されています:Hashing、Encode/Decode など。

7. JS エラーのデバッグ​

構文エラーや不正なコードなどが原因で、JavaScript のエラーが発生することがあります。コンソールのエラーメッセージを読むか、console.log() を使うことで、デバッグできます。

8. Scripting をモック API として使う​

Proxyman 2.32.0 以降では、Scripting ツールをモック API として使えます。リクエストはサーバーに送信されず、レスポンスのボディは自分で定義します。この仕組みは Map Local と同じように動作します。

実際の REST API がまだ利用できない場合に便利です。ローカルで定義してテストできます。

モック API を有効にするには:

  1. Scripting ツールを開いて、スクリプトを選択します。
  2. Script Editor の Request と Response のチェックボックスの横にある Run as Mock API のチェックボックスをオンにします(上の Script Editor のスクリーンショットを参照)。

その後は、通常どおりにレスポンスを定義できます:

function onResponse(context, url, request, response) {

// Init new body
var body = {};
body["new-key"] = "Proxyman";
response.body = body;

// Or map from a file
// response.bodyFilePath = "~/Desktop/myfile.json"

// Done
return response;
}

9. 注意事項​

  • onRequest と onResponse 関数では、request と response オブジェクトを必ず return してください。
  • Proxyman 4.16.0 以降:Proxyman はバイナリデータを Uint8Array に変換するようになりました。
  • Proxyman 4.15.0 以前:JavaScript には Data 型がないため、バイナリのボディは JavaScript で Base64 Encoded String に変換されていました。Uint8Array、blob、ArrayBuffer をボディとして渡すには、先に Base64 Encoded String に変換してください。

関連情報​