当前位置: 首页 >服务端 > 同源策略和跨域解决方案

同源策略和跨域解决方案

同源策略和跨域解决方案

 

同源策略

一个源的定义

如果两个页面的协议,端口(如果有指定)和域名都相同,则两个页面具有相同的

举个例子:

下表给出了相对http://a.xyz.com/dir/page.html同源检测的示例: 

URL结果原因
http://a.xyz.com/dir2/other.html成功 
http://a.xyz.com/dir/inner/another.html成功 
https://a.xyz.com/secure.html失败不同协议 ( https和http )
http://a.xyz.com:81/dir/etc.html失败不同端口 ( 81和80)
http://a.opq.com/dir/other.html失败不同域名 ( xyz和opq)

 

同源策略是什么

同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。所以xyz.com下的js脚本采用ajax读取abc.com里面的文件数据是会被拒绝的。

同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。

不受同源策略限制的

1. 页面中的链接,重定向以及表单提交是不会受到同源策略限制的。

2. 跨域资源的引入是可以的。但是js不能读写加载的内容。如嵌入到页面中的<script src="..."></script>,<img>,<link>,<iframe>等。

举个例子

我们手写两个Django demo:

demo1

urls.py

urlpattes = [url(r'^abc/', views.abc),]

views.py

def abc(request):retu HttpResponse("rion")

demo2

urls.py

urlpattes = [url(r'^xyz/', views.xyz),]

views.py

def xyz(request):retu render(request, "xyz.html")

xyz.html

同源策略和跨域解决方案 _ JavaClub全栈架构师技术笔记
<!DOCTYPE HTML><html><head>  <meta charset="UTF-8">  <meta http-equiv="x-ua-compatible" content="IE=edge">  <meta name="viewport" content="width=device-width, initial-scale=1">  <title>xyz</title></head><body><button id="b1">点我</button><script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script><script>  $("#b1").click(function () {$.ajax({  url: "http://127.0.0.1:8002/abc/",  type: "get",  success:function (res) {console.log(res);  }})  });</script></body></html>
同源策略和跨域解决方案 _ JavaClub全栈架构师技术笔记

现在,打开使用浏览器打开http://127.0.0.1:8000/xyz/,点击页面上的 '点我' 按钮,会在console页面发现错误信息如下:

同源策略和跨域解决方案 _ JavaClub全栈架构师技术笔记

为什么报错呢?因为同源策略限制跨域发送ajax请求。

细心点的同学应该会发现我们的demo1项目其实已经接收到了请求并返回了响应,是浏览器对非同源请求返回的结果做了拦截。

再细心点的同学会发现,我们使用cdn方式引用的jQuery文件也是跨域的,它就可以使用。

同样是从其他的站点拿东西,script标签就可以。那我们能不能利用这一点搞点事情呢?

把xyz.html中的代码改一下:

同源策略和跨域解决方案 _ JavaClub全栈架构师技术笔记
<!DOCTYPE HTML><html><head>  <meta charset="UTF-8">  <meta http-equiv="x-ua-compatible" content="IE=edge">  <meta name="viewport" content="width=device-width, initial-scale=1">  <title>xyz</title></head><body><button id="b1">点我</button><script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script><script src="http://127.0.0.1:8002/abc/"></script></body></html>
同源策略和跨域解决方案 _ JavaClub全栈架构师技术笔记

现在,我们刷新一下页面,会出现如下错误提示:

同源策略和跨域解决方案 _ JavaClub全栈架构师技术笔记

 

看来后端返回的响应已经被拿到了,只不过把rion当成了一个变量来使用,但是该页面上却没有定义一个名为rion的变量。所以出错了。

那我定义一个rion变量还不行吗?

同源策略和跨域解决方案 _ JavaClub全栈架构师技术笔记
<!DOCTYPE HTML><html><head>  <meta charset="UTF-8">  <meta http-equiv="x-ua-compatible" content="IE=edge">  <meta name="viewport" content="width=device-width, initial-scale=1">  <title>xyz</title></head><body><button id="b1">点我</button><script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script><script>  var rion = 100;</script><script src="http://127.0.0.1:8002/abc/"></script></body></html>
同源策略和跨域解决方案 _ JavaClub全栈架构师技术笔记

这次就不会报错了。

我定义一个变量可以,那可不可以定义一个函数呢?

同源策略和跨域解决方案 _ JavaClub全栈架构师技术笔记
<!DOCTYPE HTML><html><head>  <meta charset="UTF-8">  <meta http-equiv="x-ua-compatible" content="IE=edge">  <meta name="viewport" content="width=device-width, initial-scale=1">  <title>xyz</title></head><body><button id="b1">点我</button><script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script><script>  function rion() {console.log("选我不后悔!");  }</script><script src="http://127.0.0.1:8002/abc/"></script></body></html>
同源策略和跨域解决方案 _ JavaClub全栈架构师技术笔记

同时把返回的响应也改一下:

def abc(request):retu HttpResponse("rion()")

此时,再次刷新页面,可以看到下面的结果。

同源策略和跨域解决方案 _ JavaClub全栈架构师技术笔记

啊,真是让人性兴奋的操作!

我返回的 rion(),页面上拿到这个响应之后直接执行了rion函数!


 

那函数中可不可以传递参数呢?我们试一下!

 demo2中的xyz.html

同源策略和跨域解决方案 _ JavaClub全栈架构师技术笔记
<!DOCTYPE HTML><html><head>  <meta charset="UTF-8">  <meta http-equiv="x-ua-compatible" content="IE=edge">  <meta name="viewport" content="width=device-width, initial-scale=1">  <title>xyz</title></head><body><button id="b1">点我</button><script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script><script>  function rion(res) {console.log(res);  }</script><script src="http://127.0.0.1:8002/abc/"></script></body></html>
同源策略和跨域解决方案 _ JavaClub全栈架构师技术笔记

demo1中的视图函数:

def abc(request):res = {"code": 0, "data": ["SNIS-561", "SNIS-517", "SNIS-539"]}retu HttpResponse("rion({})".format(json.dumps(res)))

刷新页面查看效果:

同源策略和跨域解决方案 _ JavaClub全栈架构师技术笔记

果然传递参数也是可以的!

我们通过script标签的跨域特性来绕过同源策略拿到想要的数据了!!!


 

这其实就是JSONP的简单实现模式,或者说是JSONP的原型:创建一个回调函数,然后在远程服务上调用这个函数并且将JSON 数据形式作为参数传递,完成回调。

将JSON数据填充进回调函数,这就是JSONP的JSON+Padding的含义。

但是我们更多时候是希望通过事件触发数据的获取,而不是像上面一样页面一刷新就执行了,这样很不灵活。

其实这很好解决,我们可以通过javascript动态的创建script标签来实现。

demo2中的xyz.html

同源策略和跨域解决方案 _ JavaClub全栈架构师技术笔记
<!DOCTYPE HTML><html><head>  <meta charset="UTF-8">  <meta http-equiv="x-ua-compatible" content="IE=edge">  <meta name="viewport" content="width=device-width, initial-scale=1">  <title>xyz</title></head><body><button id="b1">点我</button><script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script><script>  function rion(res) {console.log(res);  }  function addScriptTag(src){var scriptEle = document.createElement("script");$(scriptEle).attr("src", src);$("body").append(scriptEle);$(scriptEle).remove();  }  $("#b1").click(function () {addScriptTag("http://127.0.0.1:8002/abc/")  })</script></body></html>
同源策略和跨域解决方案 _ JavaClub全栈架构师技术笔记

这样当我们点击b1按钮的时候,会在页面上插入一个script标签,然后从后端获取数据。

为了实现更加灵活的调用,我们可以把客户端定义的回调函数的函数名传给服务端,服务端则会返回以该回调函数名,将获取的json数据传入这个函数完成回调。

demo2中的xyz.html

同源策略和跨域解决方案 _ JavaClub全栈架构师技术笔记
<!DOCTYPE HTML><html><head>  <meta charset="UTF-8">  <meta http-equiv="x-ua-compatible" content="IE=edge">  <meta name="viewport" content="width=device-width, initial-scale=1">  <title>xyz</title></head><body><button id="b1">点我</button><script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script><script>  function rion(res) {console.log(res);  }  function addScriptTag(src) {var scriptEle = document.createElement("script");$(scriptEle).attr("src", src);$("body").append(scriptEle);$(scriptEle).remove();  }  $("#b1").click(function () {addScriptTag("http://127.0.0.1:8002/abc/?callback=rion")  });</script></body></html>
同源策略和跨域解决方案 _ JavaClub全栈架构师技术笔记

demo1中的views.py

def abc(request):res = {"code": 0, "data": ["SNIS-561", "SNIS-517", "SNIS-539"]}func = request.GET.get("callback")retu HttpResponse("{}({})".format(func, json.dumps(res)))

这样就能实现动态的调用了。

jQuery中getJSON方法

jQuery中有专门的方法实现jsonp。

demo2中的xyz.html

同源策略和跨域解决方案 _ JavaClub全栈架构师技术笔记
<!DOCTYPE HTML><html><head>  <meta charset="UTF-8">  <meta http-equiv="x-ua-compatible" content="IE=edge">  <meta name="viewport" content="width=device-width, initial-scale=1">  <title>xyz</title></head><body><button id="b1">点我</button><script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script><script>  $("#b1").click(function () {$.getJSON("http://127.0.0.1:8002/abc/?callback=?", function (res) {  console.log(res);})  });</script></body></html>
同源策略和跨域解决方案 _ JavaClub全栈架构师技术笔记

要注意的是在url的后面必须要有一个callback参数,这样getJSON方法才会知道是用JSONP方式去访问服务,callback后面的那个?是jQuery内部自动生成的一个回调函数名。

但是如果我们想自己指定回调函数名,或者说服务上规定了回调函数名该怎么办呢?我们可以使用$.ajax方法来实现:

同源策略和跨域解决方案 _ JavaClub全栈架构师技术笔记
<!DOCTYPE HTML><html><head>  <meta charset="UTF-8">  <meta http-equiv="x-ua-compatible" content="IE=edge">  <meta name="viewport" content="width=device-width, initial-scale=1">  <title>xyz</title></head><body><button id="b1">点我</button><script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script><script>  $("#b1").click(function () {$.ajax({  url: "http://127.0.0.1:8002/abc/",  dataType: "jsonp",  jsonp: "callback",  jsonpCallback: "rion2"})  });  function rion2(res) {console.log(res);  }</script></body></html>
同源策略和跨域解决方案 _ JavaClub全栈架构师技术笔记

不过我们通常都会讲回调函数写在success回调中:

同源策略和跨域解决方案 _ JavaClub全栈架构师技术笔记
<!DOCTYPE HTML><html><head>  <meta charset="UTF-8">  <meta http-equiv="x-ua-compatible" content="IE=edge">  <meta name="viewport" content="width=device-width, initial-scale=1">  <title>xyz</title></head><body><button id="b1">点我</button><script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script><script>  $("#b1").click(function () {$.ajax({  url: "http://127.0.0.1:8002/abc/",  dataType: "jsonp",  success: function (res) {console.log(res);  }})  })</script></body></html>
同源策略和跨域解决方案 _ JavaClub全栈架构师技术笔记

 

JSONP应用

同源策略和跨域解决方案 _ JavaClub全栈架构师技术笔记
// 跨域请求示例$("#show-tv").click(function () {  $.ajax({url: "http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403",dataType: 'jsonp',jsonp: 'callback',jsonpCallback: 'list',success: function (data) {  var weekList = data.data;  var $tvListEle = $(".tv-list");  $.each(weekList, function (k, v) {var s1 = "<p>" + v.week + "列表</p>";$tvListEle.append(s1);$.each(v.list, function (k2, v2) {  var s2 = "<p><a href='" + v2.link + "'>" + v2.name + "</a></p>";  $tvListEle.append(s2)});$tvListEle.append("<hr>");  })}  })});
同源策略和跨域解决方案 _ JavaClub全栈架构师技术笔记

 

 
 
分类: About Python
 
 
 
« 上一篇: DRF 认证、权限、限制

作者:Q1mi
来源链接:https://www.cnblogs.com/rain-chenwei/p/9520240.html

版权声明:
1、JavaClub(https://www.javaclub.cn)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。

2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。





本文链接:https://www.javaclub.cn/server/112250.html

标签:解决办法
分享给朋友:

“同源策略和跨域解决方案” 的相关文章