はじめに
初投稿です。
先日chrome拡張機能を作成したのですがCORS周りがめんどくさかったので記録を残します。
拡張機能の内容としてはマウスで英単語を選択した際に選択位置の右下にCambridge DictionaryへのリンクとWeblio英和辞典から日本語訳を表示させるものです。私は英単語を学習するとき日本語訳をチラ見してから英英辞典を見るという手順をとっているので手間を省くために作成したって感じです。
で、選択した文字列に対応するページが存在することを確認する際と日本語訳を拾ってくる際にfetch
を使用したんですがこれがCORS制約で弾かれました。調べていくとmanifest.json
周りをいじってやれば解決できそうなのでやってみました。
やり方
URLの存在確認用コードはこんな感じです。fetch
のresponse
を基に判断しますがCambridge Dictionaryは存在しないページへのリクエストは自動的にトップページにリダイレクトされていしまうのでresponse.url === url
で返答元が指定したurlかを確かめています。
function isUrlValid(url,callback){
fetch(url,{
method:"HEAD"
})
.then((response) => {
if(response.status === 200 && response.url === url){
callback(true);
}else{
callback(false);
}
})
.catch(error => {
callback(false);
});
}
ただしこのコードだけではCORSエラーが出ますのでchromeのdeclarativeNetRequest APIを用いて対応します。これは特定のルールに基づいてネットワークリクエストをブロックしたり変更したりできるようにするものらしいです(公式リファレンス)。今回は変更で使います。
書き方は下のようにしておけば少なくとも動くとは思います。
"permissions": [
"declarativeNetRequest"
],
"host_permissions": [
"<all_urls>"
],
"declarative_net_request": {
"rule_resources": [
{
"id": "1",
"enabled": true,
"path": "rules/rule1.json"
},
{
"id": "2",
"enabled": true,
"path": "rules/rule2.json"
}
]
}
permissions
はAPIのアクセス許可です。今回はdeclarative_net_request
しか使いません。
host_permissions
にはdeclarative_net_request
を許可するurlを書きます。一部chromeAPIではpermission
のほかにこいつが必要になるらしいです。今回は全てのurlからのリクエストが対象となるので<all_urls>
と書きます。
declarative_net_request
のrule_resources
に使用するjson形式のルールファイルへのpathを書きます。複数指定できます。
[
{
"id": 1,
"priority": 1,
"action": {
"type": "modifyHeaders",
"responseHeaders": [
{
"header": "Access-Control-Allow-Origin",
"operation": "set",
"value": "*"
}
]
},
"condition": {
"urlFilter": "https://dictionary.cambridge.org/dictionary/english/*",
"resourceTypes": ["xmlhttprequest"]
}
}
]
action
にネットワークリクエストに対し何をするかを書きます。今回はレスポンスヘッダの書き換えです。全てのurlからのリクエストに対するレスポンスですのでvalue
を*
にしています。
condition
にそれを行う条件を書きます。urlFilter
が書き換えの対象となるurlです。resourceTypes
はxmlhttprequest
を指定すればfetch
もできます。
補足
ちなみに後で分かったことですがfetch
をServiceWorker(要するにbackground.js
)で行う場合host_permissions
の記述は必要ありませんでした。多分そっちが正しいやり方。