CORS


ドキュメント


CORS: クロス・オリジン・リソース・シェアリング

許可: レスポンスヘッダAccess-Control-Allow-Origin


画面遷移: a formタグ

CORS対象外

<form id="myform" action="別オリジン.example.com/パス" method="post">
  <input type="text" name="key" value="value">
  <input type="text" name="キー" value="バリュ">
</form>

ACAO不要

<img src="別オリジン.example.com/パス.png">
<link href="別オリジン.example.com/パス.css" rel="stylesheet">
<script src="別オリジン.example.com/パス.js"></script>

別リソース内部利用: fetch()

ACAO指定

プリフライトある場合


プリフライト

リクエストが特定の条件に合致すると、(そのリクエスト前に)

  1. プリフライト: ブラウザが自動OPTIONSメソッドでアクセス
  2. レスポンスヘッダ: ACAO指定がある
    • なければ本来のリクエストは行われない
  3. 本来のリクエスト

プリフライトになる主な例 (いずれか)


fetch()でプリフライトになる例

const json = {キー: 'バリュ', key: 'value'}
const init = {
  method: 'POST',
  mode: 'cors',
  body: JSON.stringify(json), // これだけではtext/plain扱い
  headers: {'Content-Type': 'application/json'},
}
fetch('http://別オリジン.example.com/パス', init).then(
  res => res.text()
).then(console.log).catch(console.error)

別ドキュメント埋め込み: iframe

ACAO不要

クロス・オリジンのdocumentに直接アクセスできない

<iframe id="子" src="http://別オリジン.example.com/パス" width="100" height="100"></iframe>
<script>
  window.onload = () => {
    const childWindow = document.getElementById('子').contentWindow
    console.log(childWindow.focus, childWindow.postMessage) // アクセス可
    childWindow.document // エラー
    // Uncaught DOMException: Permission denied to access property "document" on cross-origin object
  }
</script>

iframeとの情報交換はpostMessage()を使う

送信側

window.onload = () => {
  const targetWindow = window.parent // 送信先が親のとき
  const targetOrigin = 'http://送信先ドメイン.example.com'
  targetWindow.postMessage('メッセージ', targetOrigin)
}

受信側

window.addEventListener("message", event => {
  const srcOrigin = 'http://送信元ドメイン.example.net'
  if (event.origin !== srcOrigin) return // 送信元が違えば無視
  console.log(event.data)
})