XMLHttpRequest で User-Agent を誤魔化す方法

スマホ専用のページを取りたい

chrome-extension (chrome拡張) を作っている際、バックグラウンドでスマホ専用のページを取得する必要が出てきます。
スマホ専用のページは User-Agent を誤魔化せば取得できることが往々にしてあるので、今回はそれで解決を試みました。

User-Agent 偽装

chrome拡張でUser-Agentを偽装するには、chrome.webRequestを使うのが常套手段のようです。

# background.coffee
# User-Agentの変更
chrome.webRequest.onBeforeSendHeaders.addListener(
  (details) ->
    headers = details.requestHeaders
    for i in [0..headers.length-1]
      if headers[i].name == 'User-Agent'
        headers[i].value = UserAgent
        break

    requestHeaders: headers
    {urls: ["対象URL" + '*']},
    ["blocking", "requestHeaders"]
)

# jQueryで同期取得
$.ajax(
  url: "対象URL",
  async: false,
  success: (data) ->
    console.log(data)
)

また、chrome拡張のmanifestは次の通り。
(一部削除したので、動くかな?)

{
  "manifest_version": 2,
  "name": "Ajax Tester",
  "version": "0.1",

  "description": "AjaxのUser-Agentを確認します",
  "background": {
    "persistent": true,
    "page": "html/background.html"
  },

  "permissions": [
    "webRequest",
    "webRequestBlocking",
    "対象URL"
  ]
}

chrome.webRequestを使うために、"permissions"に3つほど設定してます。対象URLをここに書いて置かないと、取得権限が無いと弾かれてしまいます

偽装できない?

これを実行すると、対象URLのページに対するUser-Agentが変更されるようになります。
・・・しかし、なぜか background.js の中で XMLHttpRequest を使ってページを取得すると、偽装に失敗してしまいます。

同期 -> 非同期

chrome.webRequestのページを見ると、次の文言がありました。
http://developer.chrome.com/extensions/webRequest.html

Also synchronous XMLHttpRequests from your extension are hidden from blocking event handlers in order to prevent deadlocks.

・・・え、同期ダメなの?

ということで、次のように変更することで、偽装に成功しました。

# jQueryで非同期取得
$.ajax(
  url: "対象URL",
  async: true, #非同期!
  success: (data) ->
    console.log(data)
)

非同期実行にすることで、background.jsの内部で発行するXMLHttpRequestでもヘッダーを書き換えることが出来るようです。

めでたしめでたし。