◆ webサーバを立ててそこを通す
  ◆ クライアントサイドで fetch を使う場合は web サーバから Access-Control-Allow-Origin の http header で接続元を許可しないとだめ
  ◆ credentials 送るときは Access-Control-Allow-Origin に "*" が使えない
    ◆ referrer からオリジン作ればどこからでも許可できる
  ◆ credentials 送るときは Access-Control-Allow-Credentials に true の設定必要
◆ chrome の拡張機能で ajax 通信を任意の URL へリダイレクト

xhr や fetch の ajax 通信で別オリジンのデータがほしいことってありますよね
特に xxx へのリクエストを yyy に置き換えて別のデータを取得して使うとか

もちろん通常は クロスオリジンはだめと怒られるわけです
なのでいつもどおり 拡張機能に頼ります


拡張機能部分は簡単に

manifest.json では background スクリプトを実行するようにします
それと permission に webRequest と webRequestBlocking を入れます
"background":{
    "scripts": ["background.js"]
},
"permissions": [ "<all_urls>",  "webRequest", "webRequestBlocking" ]

background.js の方では onBeforeRequest にリスナをつけて xmlhttprequest なら URL を変換してそこにリダイレクトするようにします
fetch でも xmlhttprequest になります
chrome.webRequest.onBeforeRequest.addListener(function(details){
if(details.type === "xmlhttprequest"){
const url = convertURL(details.url)
return {redirectUrl: url}
}
}, {urls: ["<all_urls>"]}, ["blocking"])

↑だと <all_urls> なので全部の URL に対して実行されます
必要なところだけに絞ることができます
ここに書けるパターンの書き方はちょっと複雑なので 関数の中で if 文で書くほうが楽ですし 自由度高いです


これで 特定の URL へのアクセスを好きなところへリダイレクトすることができるようになりました


ですが あくまで リダイレクトなんです

xxx への ajax 通信を yyy に書き換えられますが クロスオリジンの制限は解除できていません
apache の mod_rewrite みたいに アクセス先は xxx だとして扱ってるけど中身だけ yyy に置き換わってる となるといいのですけどそうはいかないです


なので いったん自分で立てたサーバへリダイレクトして 自分のサーバで目的のデータを取ってくるようにします
とりあえずサーバは Node.js で
> npm install node-fetch
const fetch = require("node-fetch")
require("http").createServer((req, res) => {
res.writeHead(200, {
"Content-Type": "application/json"
})
fetch(req.url.substr(1))
.then(res => res.text())
.then(res.end.bind(res))
}).listen(4567)

これを実行しておいて var.blog.jp のページから
fetch("http://localhost:4567/http://var.blog.jp", {credentials:"include"})
.then(e => e.text())
.then(e => console.log(e.substr(0,100)))
を実行してみます
Fetch API cannot load http://localhost:4567/http://var.blog.jp.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://var.blog.jp' is therefore not allowed access.
If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

これだと 普通にクロスドメイン通信しているので fetch のエラーです

エラーにもあるように Access-Control-Allow-Origin を使って クロスオリジンを許可します
const fetch = require("node-fetch")
require("http").createServer((req, res) => {
res.writeHead(200, {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*"
})
fetch(req.url.substr(1))
.then(res => res.text())
.then(res.end.bind(res))
}).listen(4567)

目的は拡張機能使ってどこの URL から来てもいいようにすることなので "*" を指定しました
すると
Fetch API cannot load http://localhost:4567/http://var.blog.jp.
A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true.
Origin 'http://var.blog.jp' is therefore not allowed access.

credentials を送る場合は "*" が使えないと言われました
今回の例では普通に全公開されてるブログなので credentials はいらないですが クッキーを保持しないといけないログインが関係する場合は credentials が必要です

credentials がいるものとして 仕方なく "*" をやめて オリジンの "http://var.blog/jp" にします
const fetch = require("node-fetch")
require("http").createServer((req, res) => {
res.writeHead(200, {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "http://var.blog.jp"
})
fetch(req.url.substr(1))
.then(res => res.text())
.then(res.end.bind(res))
}).listen(4567)

今度は
Fetch API cannot load http://localhost:4567/http://var.blog.jp.
Credentials flag is 'true', but the 'Access-Control-Allow-Credentials' header is ''.
It must be 'true' to allow credentials.
Origin 'http://var.blog.jp' is therefore not allowed access.

Access-Control-Allow-Credentials を true にしろという指令
const fetch = require("node-fetch")
require("http").createServer((req, res) => {
res.writeHead(200, {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "http://var.blog.jp",
"Access-Control-Allow-Credentials": true
})
fetch(req.url.substr(1))
.then(res => res.text())
.then(res.end.bind(res))
}).listen(4567)

ここまでやると
<!DOCTYPE html>
<html lang="ja" itemscope itemtype="http://schema.org/Blog">
<head>
<meta http-equiv

やっとでました


ちょっと面倒ですが 拡張機能で URL を置き換えたいときにはこのサーバも起動しておけば ajax のレスポンスを置き換えることができます

ただ やっぱり Access-Control-Allow-Origin に文字列で書いておくのは決まったページのみになりますし どこからでもできるようにしたいです
最終的に header にアクセス元のオリジンが出力できればいいので referrer からオリジンを取得します
const fetch = require("node-fetch")
const url = require("url")
require("http").createServer((req, res) => {
const referrer = url.parse(req.headers.referer)
res.writeHead(200, {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": referrer.protocol + "//" + referrer.host,
"Access-Control-Allow-Credentials": true
})
fetch(req.url.substr(1))
.then(res => res.text())
.then(res.end.bind(res))
}).listen(4567)

これで referrer が送られていればどこから来てもクロスドメイン許可できます

ところで Node.js は JavaScript なのですが ブラウザサイドと違い http header の "referrer" は "referer" となっています
規格の方に合わせているようです

ブラウザサイドでは fetch でも "referrer" に統一してくれていていいのですけどね
スペルミスなわけですし "referrer" とユーザは書くようにして内部の変換で最終的に送るデータで "referer" に書き換えればいいのにと思います


ところで XHR では
const fetch = require("node-fetch")
const url = require("url")
require("http").createServer((req, res) => {
const referrer = url.parse(req.headers.referer)
res.writeHead(200, {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
})
fetch(req.url.substr(1))
.then(res => res.text())
.then(res.end.bind(res))
}).listen(4567)
const x = new XMLHttpRequest()
x.open("GET", "http://localhost:4567/http://var.blog.jp")
x.send(null)
x.onload = eve => console.log(x.responseText.substr(0,100))
<!DOCTYPE html>
<html lang="ja" itemscope itemtype="http://schema.org/Blog">
<head>
<meta http-equiv

"Access-Control-Allow-Origin": "*" だけで OK でした
なんと簡単!
fetch は便利ですが 面倒な制限も増えているのですね