同源策略限制的是脚本读取跨域响应的能力,而非请求发起本身;script、img、iframe、link等标签可跨域加载资源,但JS无法读取其内容或属性。

HTML 本身不触发同源策略检查,但其中嵌入的资源(如 <script>、<img>、<iframe>)在加载时会受同源策略约束——关键不在 HTML 文件是否跨域,而在浏览器对哪些行为施加限制。
哪些 HTML 标签发起请求会受同源策略影响
同源策略(Same-Origin Policy)是浏览器对脚本读取资源的限制,不是对所有跨域请求“一刀切”拦截:
-
<script src="https://xxx.com/a.js"></script>:能加载成功,但脚本执行后无法通过 JS 读取其内部变量或错误详情(比如fetch失败时得不到响应体) -
<img src="https://xxx.com/logo.png">:可正常显示,但 JS 无法读取该图片的像素数据(canvas.drawImage()后调用ctx.getImageData()会报SecurityError) -
<iframe src="https://xxx.com/page.html">:可渲染,但父页 JS 访问其contentDocument或contentWindow会失败,除非双方都设置document.domain(仅限同主域子域)或使用postMessage -
<link rel="stylesheet" href="https://xxx.com/style.css">:CSS 可加载并生效,但无法通过 JS 读取其 CSSRule 列表(document.styleSheets[0].cssRules抛错)
为什么 fetch 和 XMLHttpRequest 跨域默认失败,而 <script> 不失败
本质区别在于「是否允许脚本读取响应内容」:
-
fetch('https://api.xxx.com/data'):浏览器要求目标服务器显式返回Access-Control-Allow-Origin响应头,否则 JS 拿不到response.text()或response.json()的结果,即使 HTTP 状态码是 200 -
<script src="https://cdn.xxx.com/lib.js"></script>:属于“宽泛跨域”(CORS-exempt),浏览器允许执行,但 JS 无法获知加载是否失败(onerror只能知道“出错了”,拿不到 status、headers 等细节) - 例外:带凭证(
credentials: 'include')的fetch还需服务端返回Access-Control-Allow-Credentials: true,且Access-Control-Allow-Origin不能为*
iframe 跨域通信的可行路径
直接访问 iframe.contentWindow 会触发 Blocked a frame with origin "xxx" from accessing a cross-origin frame 错误。替代方案只有两个可靠方向:
使用 PptxGenJS 和 Python 解析,将结构化的 HTML/CSS 幻灯片内容转换为原生、可编辑的 PowerPoint(.pptx)演示文稿。
立即学习“前端免费学习笔记(深入)”;
- 双方协作用
window.postMessage():父页发消息 → 子页监听message事件 → 子页回传 → 父页验证event.origin后处理。这是唯一无需服务端改配置的通用解法 - 服务端代理或 JSONP(仅限 GET + script 注入):适用于旧系统,但 JSONP 无状态、难调试、不支持错误重试
- 注意:
document.domain = 'example.com'仅在双方都是sub1.example.com和sub2.example.com时有效,且现代 Chrome 已限制其使用场景(如不能用于localhost)
CORS 配置常见漏项和调试技巧
后端配了 Access-Control-Allow-Origin: * 却仍报错?大概率踩了这几个坑:
- 没返回
Access-Control-Allow-Headers:前端若设置了自定义 header(如Authorization: Bearer xxx),服务端必须明确列出,不能只写*(部分浏览器不认) - 预检请求(OPTIONS)没处理:带
Content-Type: application/json或自定义 header 的请求会先发 OPTIONS,若后端未响应 200 + 正确 CORS 头,后续请求直接被拦 - Cookie/认证请求没开凭证支持:前端
fetch(url, { credentials: 'include' })要求服务端同时返回Access-Control-Allow-Credentials: true和具体域名(不能是*) - 调试建议:用
curl -I -X OPTIONS https://api.example.com/xxx看响应头;浏览器 Network 面板里找 failed 请求,点开看「Headers」→「Response Headers」是否齐全
真正容易被忽略的是:同源策略限制的是「JS 脚本读取跨域响应的能力」,而不是「能否发出请求」。很多问题本质不是“跨域不让发”,而是“发完了不让你看”。理清这个边界,比死记 CORS 配置更能避开大部分弯路。


















