“跨域”的问题来源于浏览器的同源策略(Same-Origin Policy),这是一个用于保障 Web 安全的机制。它限制了网页中加载的脚本或资源访问其他源的数据。
一.跨域的来源
什么是“源”?
一个网页的“源”由三部分构成:
协议://域名:端口号
-
协议(Protocol):如
http://
、https://
-
域名(Domain):如
example.com
-
端口号(Port):如
:80
、:443
只有这三者都相同,两个页面才属于“同源”,如果三者有其一不同,则会产生跨域
二.跨域常见的类型
1. 脚本访问跨域
通过 JavaScript 脚本(如 fetch
、XMLHttpRequest
)主动请求跨域数据(如 JSON、API 接口等),并试图读取资源的内部数据,而产生的跨域。
-
不同源之间的页面不能直接通过 JS 访问对方的 DOM。
-
比如,在使用
iframe
预览图片时。当iframe
中的图片来源与包含iframe
的页面的域名不同时,就会触发浏览器的同源策略,从而导致跨域问题。 -
<!-- 父页面(a.com)中嵌套了一个 iframe --> <iframe src="https://b.com/page.html" id="myFrame"></iframe> <script> const iframe = document.getElementById('myFrame'); console.log(iframe.contentWindow.document); // 报错:Permission denied </script> 因为 a.com 与 b.com 不同源,浏览器禁止 JS 直接访问 iframe 的内容。
2. 数据请求跨域(AJAX/Fetch)
通过 JavaScript 主动发起的数据请求(如 AJAX、Fetch),尝试从不同源(协议、域名、端口任一不同)的服务器获取数据资源,而这种行为受到浏览器 同源策略(Same-Origin Policy) 的限制
-
使用
fetch
或XMLHttpRequest
请求其他域名的数据时被浏览器拦截。 -
需要目标服务器设置 CORS 头部允许访问。
-
解决方案
- 1.后端设置cors
- 2.前端使用代理服务器
- 3.jsonp ,仅支持get请求,已过时
3. 资源加载跨域
浏览器从不同源(协议、域名、端口任一不同)加载静态资源(如图片、CSS、JS、字体、视频等)。
-
加载图片、字体、音视频、PDF 等静态资源时,若未配置 CORS,可能无法使用或被限制访问(如无法绘制到 canvas 上)。
-
解决方案
-
1. 资源服务器配置 CORS 响应头
后端服务器需返回以下 HTTP 头:
Access-Control-Allow-Origin: *
或者指定源
-
Access-Control-Allow-Origin: https://your-website.com
-
2. 前端添加
crossorigin
属性(图片、音视频、字体时需)<img src="..." crossorigin="anonymous"> <video src="..." crossorigin="anonymous"></video> <link rel="stylesheet" href="..." crossorigin="anonymous">
注意:
-
仅前端设置
crossorigin
不够,服务器必须响应带有Access-Control-Allow-Origin
,两边要配合。
4.浏览器缓存跨域---最难发现的跨域
浏览器缓存跨域,是由于浏览器的缓存机制导致的一种跨域情况。这种跨域一般会出现在浏览器通过一些无视跨域的标签和css(如img、background-image)缓存了一些图片资源之后,当再次发起图片请求时,就不会向服务器端请求数据,而是直接向浏览器请求缓存的数据,从而引起了跨域。这个时候即使服务端设置了Access-Control-Allow-Origin,但浏览器请求的是缓存,依旧会导致跨域的发生。
解决
1.设置时间戳,让浏览器以为是不同资源来防止缓存
// 在UR 后面加上时间戳参数,避免浏览器缓存导致图片不刷新。
img.src = url + '?t=' + new Date().getTime();
2.发送请求时,设置如下配置,强制刷新
const res = await fetch(url,{cache:'no-cache'})