关于web跨域问题的总结

什么是跨域

跨域是由浏览器同源策略引起的,是指页面请求的接口地址,必须与页面url地址处于同域上(即域名,端口,协议相同)。这是为了防止某域名下的接口被其他域名下的网页非法调用,是浏览器对JavaScript施加的安全限制。同源策略是浏览器最核心也最基本的安全功能,Web是构建在同源策略基础之上的,浏览器是针对同源策略的一种实现。

同源策略的三个评判指标:

  1. 协议
  2. 域名
  3. 端口号‘

下表给出了与 URL http://store.company.com/dir/page.html 的源进行对比的示例:
在这里插入图片描述表格数据来源

跨域只是浏览器单方面的行为

这里引用一篇博文,讲得挺好 →传送门

根据上面这位朋友所讲,跨域只是浏览器单方面的行为。当在一个页面需要像服务器发送请求时,不管跨没跨域首先请求是会发出去的,另外服务器也会顺利接收到请求并且响应,那么问题在哪?
是最后一步——浏览器接收响应数据!在浏览器接收响应数据之前会先检查数据是否同源,如果跨域则将数据进行拦截,从而前端访问不到响应的数据。所以说同源策略只是浏览器出于安全考虑的一个单方面行为。而在服务端,比如 服务器A 向 服务器B 请求数据是不需考虑跨域问题的。

哪些行为不受同源策略的影响

  1. 另外,需要注意的是,html里像<img>,<link>,<a>,<script>,<iframe>等这种带有
    hrefsrc 属性的标签也是不会产生跨域的,要不你想想平时使用的jquery、bootstrap 这类 cdn 呀、放图床上面的图片呀,是不是都可以顺利引用啊哈哈哈哈
  2. 页面中的链接,重定向以及 form 表单提交是不会受到同源策略限制的,所谓的同源策略,是对浏览器跨域获取数据,防止越权进行限制,在没有得到允许的情况下,不能够读取其他域名的内容。但浏览器并不阻止向其他域名发出请求。那么超链接、form 等能够跨域就可以理解,它们只是发出请求随后立即跳转页面,并不需得到响应。
  3. 还有一点,通过浏览器地址栏直接访问网页是没有跨域的说法的,只有在一个已经打开的页面里去请求另一个页面或者资源时(比如ajax)才存在跨域一说。(要不我们岂不是连baidu.com都访问不了了?笑)
// 直观来看,如下
// 地址栏访问: _ → 域     (页面压根没打开,哪里有“域”是叭)
// 页面间访问:域 → 域

如何解决跨域问题

浏览器出于信息安全考虑而应用同源策略,这一点对于用户来讲是好的,但对于作为前端开发者的我们,显然对这个东西感到极为不适。比如当需要调用一些远程接口时,如果服务端没有开放权限,那么我们是无法使用这些接口的。那么如何解决浏览器同源策略所产生的这些问题呢?

jsonp技术

大家看到 json ,嗯??!是不是倍感亲切呀哈哈,其实它俩没多大关系(???一棍子给你劝退了)
别急,回来回来~(笑)
其实这个方法一点也不复杂,保你半小时点亮技能树。json其实并不是什么新技术,它恰恰是运用原有技术的一种取巧,巧妙地实现跨域请求数据。那么,请随我慢慢道来~
我们首先需要在本机模拟一个跨域环境,这个也很容易实现,只是利用同源策略里的不同端口号即可,比如在域A下的url是http://127.0.0.1:90(客户端),域B下的url是http://127.0.0.1:91(服务端)
接着我们就可以大口大口地吃栗子啦

// 假设在域 A 的根目录下里,有这么一个文件a.html
<script>
	var a = '555~没有人执行我,我打印不出来'
</script>
<script src="http://127.0.0.1:91/b.js"></script>
// 假设在域 B 的根目录下里,有这么一个文件b.js
console.log('你好,我是来自http://127.0.0.1:91的一段文字');
console.log('你好,我很强哦,谁请求我我就打印谁:' + a);

以上结果估计大家看出来了吧,我们利用script标签不受同源策略限制这一点,获取到了另一个域里的内容,而且另一个域请求过来的js文件还对域 B 的全局变量进行了操作。
那么我们再把内容改写一下:

// 假设在域 A 的根目录下里,有这么一个文件a.html,且这个文件需要请求一件商品的数据
<script>
	function getData(data) {
		console.log(data.id);
		console.log(data.name);
		console.log(data.color);
		console.log(data.price);
	}
</script>
<script src="http://127.0.0.1:91/b.js"></script>
// 假设在域 B 的根目录下里,有这么一个文件b.js
getData({
	"id": 1212,
	"name": "apple",
	"color": "red",
	"price": 50
});

哦豁!发生了什么??!这不就跨域成功了吗?我们来捋一捋这个过程做了些什么操作

  1. 在域 A 的 a.html 里定义了一个函数,为即将需要请求过来的数据执行一些操作做好准备
  2. 在域 B 的 b.js 里将需要响应给客户端的数据作为一个实参包装进一个函数,这个函数名是和前端开发者协商好的同一个函数名getData
  3. 因为js脚本不受同源策略的影响,客户端请求(或者说引用)到服务端的 b.js 后就会执行里面的语句,这些语句配合客户端原有的语句一起,就可以访问到 b.js 发过来的数据了

再把代码改造一下就是一个异步请求的ajax版了,这不过这回需要动态创建 script 标签,毕竟在发送请求之前,引用 b.js 的 script 标签是不存在的嘛

// 假设在域 A 的根目录下里,有这么一个文件a.html,且这个文件通过点击按钮异步请求数据

<button type="button">请求jsonp数据</button>

<script>
	var btn = document.querySelector('button');
	
	btn.onclick = function() {
		var script = document.createElement('script');
		script.src = ‘http://127.0.0.1:91/b.js’;
		document.body.appendChild(script);
	}
	
	function getData(data) {
		console.log(data.id);
		console.log(data.name);
		console.log(data.color);
		console.log(data.price);
	}
</script>
<script src="http://127.0.0.1:91/b.js"></script>
// 服务端域 B 下的 b.js 不需改动
getData({
	"id": 1212,
	"name": "apple",
	"color": "red",
	"price": 50
});

那么当多个用户请求同一份jsonp文件数据时,服务端如何适应各个客户端不同的函数名呢?
这时只需在客户端将函数名作为参数发送给服务端即可

<script src="http://127.0.0.1:91/b.js?funname=callback"></script>

然后服务端接到请求后看到参数就可以知道,“原来你是要我生成一个叫callback的函数啊,ok”。接着服务端一顿猛如虎的操作后,就把函数给生成并且把数据装进函数里了(其实就是拼接字符串,囧)

// b.js 的一顿狂暴操作之后...
callback({
	"id": 1212,
	"name": "apple",
	"color": "red",
	"price": 50
});

完毕~
等等,咱们再介绍一种跨域方法

CORS技术

跨域资源共享(CORS) 是 HTTP 的一部分,它允许服务端来指定哪些主机可以从这个服务端加载资源。它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。

前面提到过,只要服务端给予相应的权限,同样可以跨域(让浏览器对其信任)
我们可以看看当产生跨域时,浏览器拦截后所给的提示:
在这里插入图片描述
操作很简单,只需在服务端给响应头添加"Access-Control-Allow-Origin"即可,比如在nodeJS里

server.on('request', function(req, res) {
	// res.setHeader('Access-Control-Allow-Origin', '*');  // 表示不限制所有访问的域名
	res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:90');  // 表示只允许特定 url 跨域
});

在这里插入图片描述
好了,以上是本博文的所有内容。
学无止境呀~

发布了20 篇原创文章 · 获赞 6 · 访问量 4010

猜你喜欢

转载自blog.csdn.net/CanMoHaiYan/article/details/105309010