はじめに

Chrome 拡張機能で外部サイトへの HTTP リクエスト時に Request Headers をカスタマイズする方法について整理した。

User Agent を変更したり、Cookie を付与したり、色々とできるようになる。

TL;DR

  • chrome.webRequest.onBeforeSendHeaders を使う
  • 一部の内容はイベントハンドラ内で参照できないし、設定しても保証されない
  • User Agent を変更したり、Cookie を付与したりできる

目次

  1. はじめに
  2. TL;DR
  3. 環境・条件
  4. 詳細
    1. Chrome 拡張機能のライフサイクル
    2. 実装方法
      1. manifest.json
      2. background.js
  5. まとめ
  6. 参考文献

環境・条件

Google Chrome バージョン: 78.0.3904.108(Official Build) (64 ビット)

詳細

リポジトリ: 17number/chrome-extension-custom-req-header-sample

Chrome 拡張機能のライフサイクル

前置き、読み飛ばしても OK。

公式: Life cycle of requests

onBeforeSendHeaders (optionally synchronous)
Fires when a request is about to occur and the initial headers have been prepared.
The event is intended to allow extensions to add, modify, and delete request headers (*).
The onBeforeSendHeaders event is passed to all subscribers, so different subscribers may attempt to modify the request; see the Implementation details section for how this is handled.
This event can be used to cancel the request.

以下は Google 翻訳。

  • リクエストが発生し、初期ヘッダーが準備されたときに発生します。
  • このイベントは、拡張機能がリクエストヘッダー(*)を追加、変更、削除できるようにすることを目的としています。
  • onBeforeSendHeaders イベントはすべてのサブスクライバーに渡されるため、異なるサブスクライバーが要求を変更しようとする場合があります。 この処理方法については、実装の詳細セクションをご覧ください。
  • このイベントを使用して、リクエストをキャンセルできます。

要約すると下記。

  • リクエストヘッダーをいじったり、リクエスト自体をキャンセルできるよ
  • 他の拡張機能にも影響あるから、気をつけてな(のはず)

注釈に書いてあるが、以下の内容に関してはイベントフック時には提供されない(らしい)。変更しても適用されない(かもしれない)。

  • Authorization
  • Cache-Control
  • Connection
  • Content-Length
  • Host
  • If-Modified-Since
  • If-None-Match
  • If-Range
  • Partial-Data
  • Pragma
  • Proxy-Authorization
  • Proxy-Connection
  • Transfer-Encoding

公式の実装例: Implementation details

実装方法

リクエストヘッダに独自要素を追加して https://www.google.co.jp にアクセス(GET)するだけの拡張機能を作る。

manifest.json

ポイントは "permissions""webRequestBlocking" を指定していること。

単に外部サイトにアクセスするだけなら "webRequest" で良いが、onBeforeSendHeaders を使うには "webRequestBlocking" も指定する(っぽい)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"manifest_version": 2,
"name": "chrome-extension-custom-req-header-sample",
"version": "1.0.0",
"background": {
"scripts": [
"jquery-3.4.1.js",
"background.js"
]
},
"permissions": [
"webRequest",
"webRequestBlocking",
"https://www.google.co.jp/*"
]
}

$.ajax を使うので、事前に Download jQuery | jQuery で jQuery を落としておく。

background.js

メインの部分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
'use strict';

chrome.webRequest.onBeforeSendHeaders.addListener(
function (details) {
let headers = details.requestHeaders;
headers.forEach(header => {
if (header.name.toLowerCase() === 'user-agent') {
header.value = 'my device';
}
});
headers.push({ name: 'hoge', value: 'fuga' });
return { requestHeaders: headers };
}, {
urls: [
"https://www.google.co.jp/*"
],
types: [
"xmlhttprequest"
]
}, [
"blocking",
"requestHeaders"
]
);

const url = "https://www.google.co.jp"
$.ajax({url: url}).done(data => console.log({data}));

イベントハンドラの引数 details.requestHeaders でリクエストヘッダが取得できる、中身は name, value を持つオブジェクトの配列。

1
2
3
4
[
{ name: 'Accept', value: '*/*' },
{ name: 'User-Agent', value: 'Mozilla/5.0...' }
]

なので、同じ構造でデータを追加したり、

1
headers.push({ name: 'hoge', value: 'fuga' });

名前が一致するものを探して値を書き換えたりできる。

1
2
3
4
5
headers.forEach(header => {
if (header.name.toLowerCase() === 'user-agent') {
header.value = 'my device';
}
});

最終的に requestHeaders をキーとしたオブジェクトを return することで、変更後のリクエストヘッダが使用される。

1
return { requestHeaders: headers };

以下は Developer tools のキャプチャ。

まとめ

  • chrome.webRequest.onBeforeSendHeaders を使う
  • 一部の内容はイベントハンドラ内で参照できないし、設定しても保証されない
  • User Agent を変更したり、Cookie を付与したりできる

参考文献

関連記事