- ■はじめに
- ■ChromeExtensionAPIとは何か?
- ■環境構築
- ■content_script.jsとbackground.jsが正しく動作しているか確認
- ■background.jsで通信を確認してみる
- ■content_script.jsに通信の情報を渡してみる。
- ■まとめ
■はじめに
こんにちは。
株式会社iimonでフロントエンドを担当している白水です。
今回は「ChromeExtensionで使えるwebRequestAPI」を使って通信を確認する方法について書いていきたいと思います。
■ChromeExtensionAPIとは何か?
ChromeExtension(拡張機能)には、ChromeExtensionで使えるAPIがあります。
例えば、
chrome.bookmarks
API は、chromeでブックマークしたら何かするchrome.i18n
APIは、ChromeExtensionを国際化対応させるchrome.tabs
APIは、ブラウザのタブシステムを操作する
などがあります。
これら含めたExtensionAPIを使うことで、ChromeExtensionだからできることが実現できます。
API リファレンス | Chrome for Developers
その中でも、今回は「webRequestAPI」を使ってみます。
chrome.webRequest | API | Chrome for Developers
■環境構築
◆リポジトリをCloneする
// SSH ❯ git clone git@github.com:shiramizu-junya/iimon-tech-blog.git // HTTPS ❯ git clone https://github.com/shiramizu-junya/iimon-tech-blog.git
まずは、環境構築のためサンプルリポジトリをCloneしてきます。
今回は2024-07-22-chrome-webrequest-api-sample
ディレクトリを使います。
npm install
を実行して、パッケージをインストールします。
npm run start
を実行して、webpack-dev-server
を起動します。
dist
配下にファイルが吐き出されたと思います。
それぞれ、何がどこに吐き出されているかは、上記画像の線を確かめてください。
◆package.jsonの説明
"devDependencies": { "@types/chrome": "^0.0.268", "clean-webpack-plugin": "^4.0.0", "copy-webpack-plugin": "^12.0.2", "ts-loader": "^9.5.1", "typescript": "^5.5.3", "webpack": "^5.93.0", "webpack-cli": "^5.1.4", "webpack-dev-server": "^5.0.4" }
"@types/chrome"
:ChromeExtensionAPIの型定義ファイル"clean-webpack-plugin"
:ビルドするときにdist配下のファイルを1度削除するために使うPluginです。"copy-webpack-plugin"
:manifest.json
やicon
などをdist配下にまるっとコピーするために使うPluginです。"ts-loader"
:TSをJSに変換するものです。"webpack"
、"webpack-cli"
、"webpack-dev-server"
:Webpackに関わるライブラリです。
◆webpack.config.jsの説明
// webpack.config.js const path = require('path'); const webpack = require('webpack'); const CopyPlugin = require("copy-webpack-plugin"); const { CleanWebpackPlugin } = require('clean-webpack-plugin'); module.exports = { // 起点となるエントリーポイントのファイル entry: { content_script: './src/index.ts', background: './src/background/background.ts', }, // dist配下に「content_script.js」と「background.js」という名前で吐き出しなさい output: { path: path.resolve(__dirname, 'dist'), filename: '[name].js', }, // moduleのimport時に拡張子を省ける設定(今回使わないです) resolve: { extensions: ['.ts', '.js'], }, // ソースマップを有効にする設定 devtool: 'inline-source-map', // webpack-dev-serverの設定 devServer: { // staticファイルをどこのパスから提供するかの設定 static: { directory: path.resolve(__dirname, 'dist'), }, // ファイルに変更があったら、メモリ上だけでなく、dist配下のファイルも書き換える設定 devMiddleware: { writeToDisk: true, }, }, // 「.ts」ファイルを「.js」ファイルに変換するときに「ts-loader」を使いなさい module: { rules: [ { test: /\.tsx?$/, use: 'ts-loader', exclude: /node_modules/, }, ], }, // WebpackのPlugin関係 plugins: [ // ファイルに変更があったら、既存のdistファイルの中身を消す設定 new CleanWebpackPlugin(), // ビルドの進捗度を表示してくれるPlugin new webpack.ProgressPlugin(), // 「manifest.json」や「public」配下のファイルはビルド不要なので、そのままdist配下の吐き出しなさいというやつ new CopyPlugin({ patterns: [ { from: path.resolve(__dirname, './manifest'), to: path.resolve(__dirname, './dist') }, { from: path.resolve(__dirname, './public'), to: path.resolve(__dirname, './dist') }, ] }) ], };
ビルドの設定は、上記のようになっています。
詳細は割愛します。
Webpackを使ってバンドルしてみる - iimon TECH BLOG
npmとwebpackに触れてみる - iimon TECH BLOG
◆manifest.jsonの説明
// manifest.json { "name": "WebRequestTestSample", "version": "1.0.0", "description": "Chrome Extension WebRequest API Test", "manifest_version": 3, "background": { "service_worker": "background.js", "type": "module" }, "content_scripts": [ { "js": [ "content_script.js" ], "matches": [ "https://www.google.co.jp/*" ] } ], "permissions": [ "webRequest", "tabs" ], "icons": { "16": "./icons/16_fox.png", "48": "./icons/48_fox.png", "128": "./icons/128_fox.png" }, "host_permissions": [ "https://www.google.co.jp/*" ] }
name
、version
、description
、manifest_version
:拡張機能の設定background
:裏側で動くJSファイルcontent_scripts
:表側で動くJSファイルpermissions
:Extensionで使うAPIのホワイトリストicons
:Extensionで表示するアイコンhost_permissions
:特定のドメインやURLへのアクセスを要求するために使用されます。拡張機能がどのウェブサイトとやりとりできるかを制御します。
Chrome拡張機能の概要から公開まで(ManifestV3対応) ~概要編~
◆ChromeExtensionのインストール
「拡張機能」のページ(chrome://extensions/
)に移動して、
「ディベロッパーツール」→「パッケージ化されていない拡張機能を読み込む」→「distファイルを選択して読み込む」と、狐マークの拡張機能が追加されます。
■content_script.jsとbackground.jsが正しく動作しているか確認
◆content_script.jsの実行確認
「googlemap」にアクセスすると、content_script.js
が実行されていることがわかります。
◆background.jsの実行確認
background.js
の実行を確認する場合は、Service Workerをクリックします。
別Windowでconsoleが起動します。
background.jsに書いているコードが実行されています。
■background.jsで通信を確認してみる
// src/background/background.ts const handleWebRequestCompleted = (details: chrome.webRequest.WebResponseCacheDetails) => { console.log(details); } chrome.webRequest.onCompleted.addListener( handleWebRequestCompleted, { urls: ['https://www.google.co.jp/search?*'] } );
src/background/background.ts
に上記コードを記載します。
https://www.google.co.jp/search?*
へのリクエストがonCompleted
(完了したら)、handleWebRequestCompleted
関数を実行するという内容になっています。
これで、GoogleMapで適当に検索すると、background.jsでログが取得されます。
このオブジェクトのURLがリクエストが投げられた先のURLになります。
■content_script.jsに通信の情報を渡してみる。
// src/index.ts // ① chrome.runtime.sendMessage('WebRequestInterceptStart', (response) => { console.log('============================='); console.log(response); console.log('============================='); }); // ② chrome.runtime.onMessage.addListener((message) => { if (message.type === 'webRequestCompleted') { console.log('Web request completed:', message.details); } });
// src/background/background.ts // ③ const getActiveTabId = () => { return new Promise((resolve: (value: number) => void, reject: (reason: Error) => void) => { chrome.tabs.query({ active: true, currentWindow: true }, (tabs: chrome.tabs.Tab[]) => { if (tabs[0]?.id) { resolve(tabs[0].id); } else { reject(new Error('TabIDの取得に失敗しました')); } }); }); }; // ④ const handleWebRequestCompleted = async (details: chrome.webRequest.WebResponseCacheDetails) => { try { const activeTabId = await getActiveTabId(); if (activeTabId) { chrome.tabs.sendMessage(activeTabId, { type: 'webRequestCompleted', details: details, }); } } catch (error: any) { console.error(error.message); } }; // ⑤ const setWebRequestListener = () => { chrome.webRequest.onCompleted.addListener(handleWebRequestCompleted, { urls: ['https://www.google.co.jp/search?*'], }); }; // ⑥ chrome.runtime.onMessage.addListener((message: string, sender, callBackFunc) => { if (message === 'WebRequestInterceptStart') { setWebRequestListener(); callBackFunc({ status: 'chrome.webRequest.onCompletedイベントをセットしました' }); } });
メッセージパッシングをsrc/background/background.ts
の⑥の処理で受け取ります。
⑥のsetWebRequestListener();
でwebRequestのイベントをセットしています。
⑤で指定した'https://www.google.co.jp/search?*’
へのリクエストが完了すると、
④のhandleWebRequestCompleted
関数が実行されます。
④の引数details
の中に通信の中身が入ってきます。
③のgetActiveTabId
関数で現在のwindow(currentWindow: true
)でアクティブなタブ(active: true
)の情報を取得して、アクティブなタブのIDを返しています。
④でアクティブなタブに対して、{ type: 'webRequestCompleted', details: details, }
でdetails(通信情報)を返しています。
src/index.ts
の②でsrc/background/background.ts
からのメッセージパッシングを受け取って、通信の情報をcontent_script.js
側で出力しています。
これで、content_script.js側でどんな通信が走ったのか取得することができます。
■まとめ
検索条件が複数あって1つ1つのパラメーターを調べるのは無理だけど、通信の中身(ex. ユーザーがどんな検索をしたのか)知りたいなどのときに便利かなと思いました。
他にもChromeExtensionならではのAPIがあるので、試していければなと思います。
ここまで読んでくださってありがとうございました。
また、弊社ではエンジニアを募集しております。
ぜひカジュアル面談でお話ししましょう!
ご興味ありましたら、ご応募ください!