前端人员都懂的浏览器的同源策略,以及如何进行不同源间的相互访问

举报
零一01 发表于 2021/07/16 00:13:17 2021/07/16
【摘要】 同源策略 引言正文一、同源策略的定义二、同源策略的应用三、实现不同域的脚本文件访问(1)通过html几个特殊的标签进行访问(2)通过jsonp来实现跨域请求(3)通过CORS(跨域资源共享)实现跨域请求(4)通过代理实现跨域请求 结束语 引言 作为前端开发人员,你要是连同源策略都不知道是什么,那就太说不过去了。本篇文章将讲述同源策略的定义, 以...

引言

作为前端开发人员,你要是连同源策略都不知道是什么,那就太说不过去了。本篇文章将讲述同源策略的定义, 以及当我们需要克服同源策略,如何进行跨域访问数据的方法。

  • 公众号:前端印象
  • 不定时有送书活动,记得关注~
  • 关注后回复对应文字领取:【面试题】、【前端必看电子书】、【数据结构与算法完整代码】、【前端技术交流群】

正文

一、同源策略的定义

同源策略: 浏览器自带的一种安全策略,他是指协议域名端口 三个都相同的才能互相访问,即若协议、域名、端口有一个不相同时,浏览器禁止页面加载或执行与自身不同域的脚本。

那既然有同源的概念,那必定有不同源的概念,接下来我们来看一个组例子, 理解一下什么是同源,什么是不同源。

url 是否同源(以及原因)
http://www.example.com:80 该 url 与下列的 url 比较
http://www.example.com:80/index.html 同源(协议、域名、端口都相同)
http://www.example.com:5000 不同源(端口不同
https://www.example.com:80 不同源(协议不同
http://www.each.com:80 不同源(域名不同

为什么浏览器会有同源策略? 因为如果没有同源策略,别人就可以轻松的获取我们网站的 cookie 信息, 或是对网页进行DOM操作, 要知道这都是非常恐怖的, 尤其是 cookie 信息, 它里面存在着 sessionID ,这是与服务端的 session 会话的重要凭证, 要是被别人得到了 cookie , 可能会造成数据被盗取等后果。

二、同源策略的应用

上面了解了同源策略的定义,但是那还是挺抽象的,那我们接下来来看一下实战中的同源策略是什么样的,借此来更深刻的理解一下同源策略的定义。

我们的主体网址是: http://localhost:5000/

  • 请求与自身同域的脚本文件

我们通过jquery的 ajax 来请求 http://localhost:5000/ 下的 data.js 脚本文件

<!DOCTYPE html>
<html lang="en">
<head> <meta charset="UTF-8"> <title>Title</title>
</head>
<body>

<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script> $.ajax({ url: 'http://localhost:5000/data.js', type: 'get'
	})
	.done(data => { console.log(data)
	}) </script>

</body>
</html>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

因为 http://localhost:5000/data.jshttp://localhost:5000/ 是同源的,所以成功请求到了 data.js 脚本文件中的数据, 浏览器也没有报错。

  • 请求与自身不同域的脚本文件

我们通过jquery的 ajax 来请求 http://www.example.com:5000/ 下的 data.js 脚本文件

<!DOCTYPE html>
<html lang="en">
<head> <meta charset="UTF-8"> <title>Title</title>
</head>
<body>

<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script> $.ajax({ url: 'http://www.example.com:5000/data.js', type: 'get'
	})
	.done(data => { console.log(data)
	}) </script>

</body>
</html>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

因为 http://www.example:5000/data.jshttp://localhost:5000/ 是不同源的,所以浏览器会报出以下错误:
在这里插入图片描述
这个错误大致的意思就是说因为浏览器的同源策略,无法通过该域的网址去访问别的域下的脚本文件, 这就是浏览器同源策略起到的作用。

想必大家已经对同源策略有了一定的了解了。那么如果我们有时真的要去访问别的域下的脚本文件,但因为浏览器存在同源策略,那我们该怎么办呢?继续往下看, 看看如何解决这一问题。

三、实现不同域的脚本文件访问

实现不同域的脚本文件访问的方法有很多种,以下举几个例子:

  1. 通过html几个特殊的标签进行访问
  2. 通过jsonp来实现跨域请求
  3. 通过CORS(跨域资源共享)实现跨域请求
  4. 通过代理实现跨域请求(例如nginx 、node中间件)

(1)通过html几个特殊的标签进行访问

其实在 html 里有几个标签是存在 src 属性的,例如 <script><link>img<iframe>。 这些标签的 src 属性是不会受到浏览器的同源策略的限制,是可以对不同域下的脚本文件进行访问的。举个例子:

<!DOCTYPE html>
<html lang="en">
<head> <meta charset="UTF-8"> <title>Title</title>
</head>
<body>

<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>

</body>
</html>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

我们应该都知道 jquery 可以用外部链接引入吧,这就是通过 src 属性,避开了同源策略的限制的一个典型例子。

(2)通过jsonp来实现跨域请求

看到 jsonp 就能猜到,这个方法是在需要跨域请求数据时用到的,接下来我们直接来看如何使用。

  • 原生实现jsonp跨域请求
<!DOCTYPE html>
<html lang="en">
<head> <meta charset="UTF-8"> <title>Title</title>

</head>
<body>
//在script标签的src属性后面,拼接上一个 callback=回调函数名
<script src="http://www.example.com:5000/data.js?callback=showDate"></script>
<script>
	//会在跨域请求后,调用该函数 function showDate(data) { console.log(data) }
</script>
</body>
</html>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • jquery 实现 jsonp跨域请求

实际上jquery 将jsonp封装在 ajax请求中,原理的话其实就是创建了一个script标签,然后拼接 url 字符串,作为 src 属性的值。

<!DOCTYPE html>
<html lang="en">
<head> <meta charset="UTF-8"> <title>Title</title>
</head>
<body>

<script src="node_modules/jquery/dist/jquery.min.js"></script>
<script> $(function () { function showDate(data) { console.log(data) } $.ajax({ url: 'http://www.example.com:5000/data.js', type: 'get', //请求方式必须为 get dataType: 'jsonp', //数据类型改为 jsonp jsonpCallback: 'showDate'   //数据返回后调用的回调函数 }) .done(data => { console.log(data) }) })
</script>

</body>
</html>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

这样就实现了跟原生一样的通过 jsonp 实现跨域请求的效果。

(3)通过CORS(跨域资源共享)实现跨域请求

CORS 这个缩写是不是特别看着特别眼熟?没错,在上面我们做了一个跨域请求报错的实例,图中的报错信息就有这个缩写单词在内, 所以通过CORS(跨域资源共享)也是可以实现跨域请求。 因为这个我研究的不太深,我就简单来说一下怎么用吧。

我们需要向 http://www.example.com:5000/ 请求它下面的 data.js 脚本文件, 我们就只需要服务端给相应头设置一下属性即可,即可完成无论谁跨域请求该域下的 data.js , 都不会因为同源策略而报错, 所以其实这个也有点不太好, 谁都可以访问,那岂不是很危险。

Access-Control-Allow-Origin:*
Access-Control-Allow-Methods:POST,GET,OPTIONS
Access-Control-Allow-Headers:Origin,x-requested-with,content-type,Accept

  
 
  • 1
  • 2
  • 3

这个方法我描述的比较模糊, 因为我也没有深入研究过,所以可能会有点错误,但这确实是一种跨域请求的方法,如果有感兴趣的小伙伴可以去看一下阮一峰老师的一个讲解CORS的日志——跨域资源共享 CORS 详解 - 阮一峰的网络日志

(4)通过代理实现跨域请求

我们都知道同源策略是浏览器自带的,那么我们如果要避免同源策略进行跨域请求,我们可以通过代理服务器的方式进行请求,例如我们请求一个与自身不同域的脚本文件,那么我们可以先请求与自身同域的一个 url ,然后通过代理服务器进行跳转, 最后返回由代理服务器请求到的脚本文件,这样说比较抽象,我们用一个node的中间件来举例说一下(其实nginx也可以):

//引入 express 框架
const express = require('express');
//引入 代理中间件
const { createProxyMiddleware } = require('http-proxy-middleware');
//创建服务实例
const app = express();

// 使用一下代理中间件,第一个参数为我们需要代理的 url
// 第二个参数为跳转的 url
app.use('/api', createProxyMiddleware({ target: 'http://www.example.com:5000', changeOrigin: true }));

//监听5000端口
app.listen(5000);

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

按照以上配置完以后, 我们请求 http://localhost:5000/api/data.js 时, 代理服务器就会自动跳转到 http://www.example.com:5000/data.js , 这样的话我们就完成跨域请求, 并且浏览器也不会报错。

如果想具体学习一下的小伙伴可以去 github 上看一下这个中间件作者的详细介绍,下面附上跳转的链接——http-proxy-middleware的GitHub地址

其实 nginx也可以完成代理的作用,这里就不多做解释了,如果想要了解的可以去查询一下文档,自行学习一下。

结束语

好了,关于同源策略也介绍的差不多了, 有些写的详细,有些写的简略,那也是作者的水平的体现了, 等我以后水平高了,会继续完善该文章的。希望本篇文章对大家能有所帮助, 若有哪里写的不对, 也欢迎大家评论指正,谢谢~

文章来源: lpyexplore.blog.csdn.net,作者:「零一」,版权归原作者所有,如需转载,请联系作者。

原文链接:lpyexplore.blog.csdn.net/article/details/106402136

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。