一、一个源的定义

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

      下表给出了相对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里面的文件数据是会被拒绝的。

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

三、基于jsonp实现的跨域请求

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

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

下面来分步举例详细阐述其中的奥妙:

1、先开两个项目,

项目1(http://127.0.0.1:8000/)
项目2(http://127.0.0.1:8100/)

项目1

url:
url(r'index1/$',views.index1)views:def index1(request):
return  HttpResponse('wangjifei')

项目2

url:
url(r'index2/$',views.index2)views  :
def index2(request):return render(request,'index2.html')index2.html:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>同源策略</title>
</head>
<body><button id="btn">提交</button><script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js">    </script>
<script>$('#btn').click(function () {$.ajax({url:"http://127.0.0.1:8000/index1/",type:'get',success:function (res) {console.log(res)}})})
</script>
</body>
</html>

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

img_e5da7cd1aafdc8af8235d08120e0b016.png

微信图片_20180823142349.png

为什么报错呢?因为同源策略限制跨域发送ajax请求。
细心点的同学应该会发现我们的demo1项目其实已经接收到了请求并返回了响应,是浏览器对非同源请求返回的结果做了拦截。
再细心点的同学会发现,我们使用cdn方式引用的jQuery文件也是跨域的,它就可以使用。
同样是从其他的站点拿东西,script标签就可以。那我们能不能利用这一点搞点事情呢?

2、把index2.html中的代码改一下:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>同源策略</title>
</head>
<body><button id="btn">提交</button><script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js">    </script>
<script src="http://127.0.0.1:8000/index1/"></script>
</body>
</html>

现在刷新一下会出现如下错误:

img_e0fd1d37aeeb594235f2a679f69b02b3.png

微信图片_20180823143053.png

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

3、那我们就在index2.html中定义一个wangjifei变量看看:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>同源策略</title>
</head>
<body><button id="btn">提交</button><script>var wangjifei = 123
</script>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js">    </script>
<script src="http://127.0.0.1:8000/index1/"></script>
</body>
</html>

刷新发现不报错了,

img_9d7e06b90b2a11b0bc0fc97cd463a964.png

微信图片_20180823143436.png

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

index2.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>同源策略</title>
</head>
<body><button id="btn">提交</button><script>function wangjifei() {console.log('出手就要专业')}
</script>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js">    </script>
<script src="http://127.0.0.1:8000/index1/"></script>
</body>
</html>

项目1中的views:也修改一下

def index1(request):
return  HttpResponse('wangjifei()')

刷新一下页面显示结果:

img_c1d83c37ee14773eb220cc84773e84d7.png

微信图片_20180823145716.png

结果分析:返回的 wangjifei(),页面上拿到这个响应之后直接执行了wangjifei函数!

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

index2.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>同源策略</title>
</head>
<body><button id="btn">提交</button><script>function wangjifei(res) {console.log(res)}
</script>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js">    </script>
<script src="http://127.0.0.1:8000/index1/"></script>
</body>
</html>

项目1中的 views

from django.http import HttpResponse
import jsondef index1(request):ret={'code':1,'msg':[110,119,120,12306]}res = json.dumps(ret)return  HttpResponse(f'wangjifei({res})')

刷新之后显示结果:

img_9ca47ed83fa49681c2e5b01b9815acc4.png

微信图片_20180823151309.png

果然传递参数也是可以的!我们通过script标签的跨域特性来绕过同源策略拿到想要的数据了!!!

这其实就是JSONP的简单实现模式,或者说是JSONP的原型:创建一个回调函数,然后在远程服务上调用这个函数并且将JSON 数据形式作为参数传递,完成回调。
将JSON数据填充进回调函数,这就是JSONP的JSON+Padding的含义。
但是我们更多时候是希望通过事件触发数据的获取,而不是像上面一样页面一刷新就执行了,这样很不灵活。

6、我们可以通过javascript动态的创建script标签来实现。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>同源策略</title>
</head>
<body><button id="btn">提交</button><script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js">    </script>
<script>//自定义的函数function wangjifei(res) {console.log(res)}//jquery给button绑定点击事件$('#btn').click(function () {//创建一个script标签var scriptEle = document.createElement('script');//给标签添加src属性,并添加对应的属性值    http://127.0.0.1:8000/index1$(scriptEle).attr('src','http://127.0.0.1:8000/index1');//将创建好的标签添加到页面中,标签添加后就会自动触发get请求$('body').append(scriptEle);//将标签移除$(scriptEle).remove()})
</script>
</body>
</html>

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

7、为了实现更加灵活的调用,我们可以把客户端定义的回调函数的函数名传给服务端,服务端则会返回以该回调函数名,将获取的json数据传入这个函数完成回调。这样就能实现动态的调用了。修改代码如下:

index2.html代码:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>同源策略</title>
</head>
<body><button id="btn">提交</button><script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js">    </script>
<script>//自定义的函数function xxx(res) {console.log(res)}//jquery给button绑定点击事件$('#btn').click(function () {//创建一个script标签var scriptEle = document.createElement('script');//给标签添加src属性,并添加对应的属性值    http://127.0.0.1:8000/index1?callback=xxx$(scriptEle).attr('src','http://127.0.0.1:8000/index1?callback=xxx');//将创建好的标签添加到页面中,标签添加后就会自动触发get请求$('body').append(scriptEle);//将标签移除$(scriptEle).remove()})
</script>
</body>
</html>

项目1中views:

from django.http import HttpResponse
import jsondef index1(request):ret={'code':1,'msg':[110,119,120,12306]}res = json.dumps(ret)callback = request.GET.get('callback')return  HttpResponse(f'{callback}({res})')

四、jQuery中getJSON方法介绍:

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

index2.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>同源策略</title>
</head>
<body>
<button id="btn">提交</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js">        </script>
<script>//jquery给button绑定点击事件$('#btn').click(function () {$.getJSON("http://127.0.0.1:8000/index1?callback=?",function (res) {console.log(res)})})
</script>
</body>
</html>

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

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

index2.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>同源策略</title>
</head>
<body>
<button id="btn">提交</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js">    </script>
<script>//jquery给button绑定点击事件$('#btn').click(function () {$.ajax({//要访问的urlurl:"http://127.0.0.1:8000/index1/",//要处理的数据类型jsonpdataType:'jsonp',//自定义回调函数名必要参数jsonp:'callback',//自定义回调函数名,url中callback=后面的函数名jsonpcallback:'wangjifei'})});//回调函数function wangjifei(res) {console.log(res)}
</script>
</body>
</html>

views:

from django.http import HttpResponse
import jsondef index1(request):ret={'code':1,'msg':[110,119,120,12306]}res = json.dumps(ret)callback = request.GET.get('callback')return  HttpResponse(f'wangjifei({res})')

3、用ajax技术通常将回调函数写在成功回调函数的位置:

index2.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>同源策略</title>
</head>
<body>
<button id="btn">提交</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js">    </script>
<script>//jquery给button绑定点击事件$('#btn').click(function () {$.ajax({//要访问的urlurl:"http://127.0.0.1:8000/index1/",//要处理的数据类型jsonpdataType:'jsonp',//success回调success:function (res) {console.log(res)}})});//回调函数function wangjifei(res) {console.log(res)}
</script>
</body>
</html>

最后来一个jsonp的实际应用:

 <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>同源策略</title></head><body><button id="show-tv">提交</button><div class="tv-list"></div><script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script><script>$("#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;console.log(weekList);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>");})}})});</script></body></html>

五、基于Core方法解决跨域请求

  • 我们介绍了jsonp解决跨域请求问题,这种解决方式很好的诠释了跨域请求的本质,但是略显麻烦,是否还记得在我们不做任何处理的时候,跨域请求时候浏览器给我们报的错误不?翻译过来就是因为响应头没有指定Access-Control-Allow-Origin所允许原始的请求路径,因此原始请求路径http://127.0.0.1:8001不被允许访问。 基于上述的原因解释,我们只需要在响应的内容加入上述这样的授权字段,便可解决。

  • 简单请求的定义
    只要同时满足以下两大条件,就属于简单请求,不满足就是复杂请求!!!
    1.(1) 请求方法是以下三种方法之一:
    -- HEAD,GET,POST
    2.(2)HTTP的头信息不超出以下几种字段:
    -- Accept
    -- Accept-Language
    -- Content-Language
    -- Last-Event-ID
    -- Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

由于django的所有请求响应都要走中间件,所以可以写一个跨域的中间件来解决跨域问题

from django.utils.deprecation import MiddlewareMixin
class MyCore(MiddlewareMixin):def process_response(self, request, response):response['Access-Control-Allow-Origin'] = "*"  //简单请求if request.method == "OPTIONS":# 复杂请求 预检response['Access-Control-Allow-Headers'] = "Content-Type"response['Access-Control-Allow-Methods'] = "POST, DELETE, PUT"return response

同源策略和跨域请求解决方案相关推荐

  1. ajax背景、ajax对象、ajax状态、ajax与http、ajax请求数据接口、同步与异步、ajax请求XML数据、封装ajax函数、artTemplate简介、同源策略和跨域请求、JSONP

    AJAX简介: ajax背景: 1.AJAX(Asynchronous JavaScript And Xml)异步的 JavaScript 和 XML:ajax是浏览器提供的一套API,最早出现在谷歌 ...

  2. 服务器安全:浏览器同源策略与跨域请求、XSS攻击原理及防御策略、如何防御CSRF攻击

    主要包括 浏览器同源策略与跨域请求 XSS攻击原理及防御策略 如何使用SpringSecurity防御CSRF攻击 CC/DDOS攻击与流量攻击 什么是SSL TLS HTTPS? 一.浏览器的同源策 ...

  3. 浏览器同源策略以及跨域请求时可能遇到的问题

    跨域请求基础知识 浏览器的同源策略 浏览器的源指的是 协议://域名:端口 这样的URL组合.我们首先要明确几点 www.foo.com 和 foo.com 是不同域 www.foo.com 和 ww ...

  4. 浏览器的同源策略和跨域请求_学习版

    目录 同源策略 : 跨域请求 : 跨域请求的常见解决方案 : 1. jsonp 2. cors(跨域资源共享) 3. proxy(代理) 同源策略 : 什么是同源策略 ? + 同源策略是  浏览器  ...

  5. Django - - 进阶 - - 同源策略和跨域解决方案

    目录 同源策略 一个源的定义 同源策略是什么 举个例子 jQuery中getJSON方法 JSONP应用 1, 同源策略 1.1 一个源的定义 如果两个页面的协议,端口(如果有指定)和域名都相同,则两 ...

  6. 浏览器的同源策略与跨域问题的解决方案

    浏览器的同源策略与跨域问题的解决方案 参考文章: (1)浏览器的同源策略与跨域问题的解决方案 (2)https://www.cnblogs.com/yanggb/p/10735763.html 备忘一 ...

  7. 同源策略和跨域解决方案

    同源策略 一个源的定义 如果两个页面的协议,端口(如果有指定)和域名都相同,则两个页面具有相同的源. 举个例子: 下表给出了相对http://a.xyz.com/dir/page.html同源检测的示 ...

  8. 浏览器的同源策略及跨域解决方案

    同源策略 一个源的定义 如果两个页面的协议,端口(如果有指定)和域名都相同,则两个页面具有相同的源. 举个例子: 下表给出了相对http://a.xyz.com/dir/page.html同源检测的示 ...

  9. websocket中发生数据丢失_tcp协议;websocket协议;同源策略和跨域

    tcp协议 为什么连接的时候是三次握手,关闭的时候却是四次握手? 答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文.其中ACK报文是用来应答的,SYN报 ...

最新文章

  1. 手机长时间不用自动断网_不用蓝牙的感应音箱,只需百元!放上手机自动播放,媲美千元音质...
  2. 网络推广外包专员浅析为什么说企业网站都需要网络推广外包?
  3. Fast RCNN 训练自己的数据集(3训练和检测)
  4. Linux 访问文件的acl信息,linux文件权限管理与ACL访问控制列表
  5. kotlin学习之解构声明(十二)
  6. Mac OS X中配置Apache
  7. django的admin管理后台到底是否靠谱呢
  8. Java中的传值与传引用
  9. Spring+SpringMVC+Mybatis 多数据源整合
  10. chosen jquery ajax搜索,基于chosen插件实现人员选择树搜索自动筛选功能
  11. Python之快速排序算法实现(二)
  12. VirtualBox虚拟机移到另外一台机器,需要在设置中禁用usb
  13. Vbs脚本编程简明教程之十二
  14. Qt Creator 使用教程
  15. java定时器定时发短信,定时任务(如:定时发送短信信箱等)
  16. C语言基础丨运算符之条件运算符(七)
  17. 【Java进阶营】Java面试题收集
  18. bottom sheets_Excel 2013中的SHEET和SHEETS函数
  19. shell读取键盘输入
  20. 关于将AAB转化为APK

热门文章

  1. 吴恩达《深度学习专项》笔记+代码实战(三):“浅度”神经网络
  2. 虚拟机增加磁盘空间(VMware虚拟机)
  3. Spring Redis工具类
  4. 一些设计模式阐述,偏JAVA实现
  5. Android系统8.0及以上开启Service必须创建显示“XX应用正在运行”通知问题处理
  6. 农产品商城毕业设计,农产品销售系统毕业设计,农产品电商毕业设计论文方案需求分析作品参考
  7. 分布式事务 解决方案
  8. Docker + PostgreSQL 主从环境搭建
  9. JAVA中字符串倒序、判断名字中英文、判断手机号格式以及正则表达式应用
  10. angular2跳转路由, 获取路由参数