Skip to content

跨域隔离检测

输入任意网站的网址,查看它是否启用了跨域隔离,以及 SharedArrayBuffer多线程 WebAssembly 能否在那里运行。检测工具会读取该网址的 Cross-Origin-Opener-PolicyCross-Origin-Embedder-Policy 响应头,并告诉你缺少了什么。它只读取响应头,不会获取或存储其他任何内容。

为什么跨域隔离对网页游戏很重要

一些非常有用的浏览器能力被锁在跨域隔离之后,对游戏来说最关键的就是 SharedArrayBuffer,也就是让多线程 WebAssembly 成为可能的共享内存。如果你的引擎发布了多线程网页构建,没有它就无法运行:

  • Godot 的网页导出过去一直需要 SharedArrayBuffer(Godot 4.3+ 新增了单线程导出,以避免使用这些响应头)。
  • Unity 的多线程 WebGL 构建需要它。
  • Emscripten pthreadsffmpeg.wasm 以及许多物理和编解码库也需要它。

没有隔离,浏览器还会停用高精度计时器和 performance.measureUserAgentSpecificMemory()。所以如果多线程游戏悄无声息地加载失败,或者 performance.now() 的精度看起来异常粗糙,隔离检测就是首先要做的事。

跨域隔离的工作原理

当页面在 HTML 文档上发送以下两个响应头时,它就成为跨域隔离的页面:

Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp

COOP: same-origin 会把页面与其他非同源的窗口切断联系。COEP: require-corp 表示每个子资源都必须显式选择加入才能被嵌入。当两者都设置好后,self.crossOriginIsolated 会变为 true,SharedArrayBuffer 也随之解锁。

难点在于 COEP:一旦开启,每个跨域资源(CDN 图片、字体、脚本、iframe)都必须发送 Cross-Origin-Resource-Policy: cross-origin,或者通过 CORS 获取,否则浏览器会将其阻止。这通常就是站点出问题的地方。如果你无法控制自己的第三方资源,可以改用 Cross-Origin-Embedder-Policy: credentialless,它会以不带凭据的方式加载跨域资源,而不要求它们选择加入。

如何启用

Cloudflare Pages(一个 _headers 文件):

/*
  Cross-Origin-Opener-Policy: same-origin
  Cross-Origin-Embedder-Policy: require-corp

Vite 开发服务器vite.config.js):

js
export default {
  server: {
    headers: {
      'Cross-Origin-Opener-Policy': 'same-origin',
      'Cross-Origin-Embedder-Policy': 'require-corp',
    },
  },
}

nginx

add_header Cross-Origin-Opener-Policy same-origin;
add_header Cross-Origin-Embedder-Policy require-corp;

itch.io:在你的 HTML 游戏嵌入选项中启用 “SharedArrayBuffer support”,它会替你设置好这些响应头。

部署后,重新加载并重新运行检测工具。crossOriginIsolated 应该会翻转为 true

常见问题

如何检查我的页面是否启用了跨域隔离?

在上面的检测工具中输入你网站的网址。它会在服务端读取页面的 Cross-Origin-Opener-PolicyCross-Origin-Embedder-Policy 响应头,并告诉你这种组合是否让页面实现了隔离。如果想在自己的浏览器中做运行时检查,可以打开页面并在控制台中运行 crossOriginIsolated,当隔离生效时它会返回 true

为什么 SharedArrayBuffer 是 undefined?

浏览器只向跨域隔离的页面暴露 SharedArrayBuffer。如果它是 undefined,说明你的页面缺少 Cross-Origin-Opener-Policy: same-originCross-Origin-Embedder-Policy: require-corp 响应头,或者某个跨域资源在 COEP 下阻止了隔离。设置好这些响应头(见上文)并重新测试。

COOP 和 COEP 是什么?

Cross-Origin-Opener-Policy(COOP)控制页面如何与其他浏览窗口交互。Cross-Origin-Embedder-Policy(COEP)控制哪些子资源可以被嵌入。把 COOP: same-originCOEP: require-corp 一起设置,会让页面实现跨域隔离,从而解锁 SharedArrayBuffer 和其他强大功能。

我的 WebAssembly 游戏在浏览器里加载不出来,是这个原因吗?

通常是的。多线程 WebAssembly 构建(某些 Godot 和 Unity 网页导出、Emscripten pthreads、ffmpeg.wasm)需要 SharedArrayBuffer,而它需要跨域隔离。如果上面的检测工具显示 “未配置跨域隔离”,请设置 COOP/COEP 响应头,或者在可行的情况下改用引擎的单线程构建。

我需要 Cross-Origin-Resource-Policy 响应头吗?

在你要隔离的页面上不需要。让文档实现跨域隔离的是 COOP 和 COEP,它们放在文档上。Cross-Origin-Resource-Policy(CORP)是一个方向相反的不同响应头:你把它放在某个跨域资源(图片、字体或脚本)上,这样使用 COEP: require-corp 的页面才被允许嵌入它。所以如果检测工具在你的页面上显示 CORP “未设置”,那是预期之内、完全正常的。你只需要给其他隔离页面需要加载的资源添加 CORP。

启用 COEP 会破坏我的第三方嵌入内容吗?

有可能。开启 COEP: require-corp 后,每个跨域资源都必须发送 Cross-Origin-Resource-Policy 或使用 CORS,否则就会被阻止。如果你嵌入了无法控制的 CDN 资源或第三方脚本,可以改用 COEP: credentialless,从而避免这一要求。

相关内容