一、同源策略
同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,
如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。
可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
同源策略,它是由Netscape提出的一个著名的安全策略。现在所有支持JavaScript 的浏览器都会使用这个策略。
所谓同源是指,域名,协议,端口相同。当一个浏览器的两个tab页中分别打开来 百度和谷歌的页面当浏览器的百度tab页执行一个脚本的时候会检查这个脚本是属于哪个页面的,
结果:
二、跨域
所谓的跨域就是请求的并不是本地url,具体实例请看:
现在在项目1通过ajax访问项目2的页面(8001访问8002):
点击按钮发现并没有返回我们希望看到的,那到底是哪一步出现了问题了:
在项目2的后台,我们看到:
证明了已经处理了,难道是接收被拦截了,在火狐查看前端页面:
问题很明显就是被拦截了,为什么被拦截了?我只能说这是一种安全措施,这是在浏览器设计之初就已经规定好的,一直延续至今。
三、跨域的解决方法
在实际工作中,由于在大互联网时代,各行各业分工十分细化,单就大数据而言,
有些公司专门做数据收集、有些公司只做数据处理、而有些只做销售,这些公司传输数据的手段就是跨域请求。
下面会讲解三种解决跨域的方法:
1.借助script标签实现跨域
我们常用的Jquery可以这样:
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
在项目启动进行加载的时候,就会去对应的服务器取数据,利用这种特性可以实现跨域请求:
返回一个func(),这样在前端:
最后就能打印其中的数据了。
如果把需要传递的数据放在括号里面,就能把它取出来了,这样就可以达到跨域请求的目的了。
为了达到数据的丰富性,我们可以先进行序列化。
最后实现的代码详解:
前端代码:
<!DOCTYPE html> <html lang="en"> <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>Title</title> <script src="/static/jquery-3.2.1.min.js"></script> </head> <body> <h3>这是项目1</h3> <button class="b1">send a ajax</button> {% csrf_token %} <script> function func(s) { console.log(s) } function cross_domain(url) { {# 定义一个标签,添加一个url元素,将其添加到body里面#} {# 为了不每次点击都会加载一个script标签,每次加载之后就删除#} var $ele_script = $("<script>"); $ele_script.attr("src",url); $ele_script.attr("class","cs"); $("body").append($ele_script); $(".cs").remove() } {# 点击按钮的时候就会触发,此时才会加载<script>#} {# 使用callback=func可以将后端传输字符串进行解耦,在后端可以接收callback,这样再传递func()到前端#} $(".b1").click(function () { cross_domain("http://127.0.0.1:8002/ajax_send/?callback=func") }) </script> </body> </html>
后端代码:
from django.shortcuts import render,HttpResponse def index(request): return render(request,"index.html") import json def ajax_send(request): dict = {"name":"kebi"} func =request.GET.get("callback") #这样可以不用固定函数名 return HttpResponse("%s(%s)"%(func,json.dumps(dict)))
这其实就是JSONP的简单实现模式,或者说是JSONP的原型:创建一个回调函数,
然后在远程服务上调用这个函数并且将JSON 数据形式作为参数传递,完成回调。
jsonp是json用来跨域的一个东西。原理是通过script标签的跨域特性来绕过同源策略。
将JSON数据填充进回调函数,这就是JSONP的JSON+Padding的含义。
一般情况下,我们希望这个script标签能够动态的调用,而不是像上面因为固定在html里面所以没等页面显示就执行了,很不灵活。
我们可以通过javascript动态的创建script标签,这样我们就可以灵活调用远程服务了。
2.jQuery对JSONP的实现
(1)getJSON
jQuery框架也当然支持JSONP,可以使用$.getJSON(url,[data],[callback])方法:
项目一前端部分:
<script> $(".b1").click(function () { $.getJSON("http://127.0.0.1:8002/ajax_send/?callback=?",function (data) { {# callback=?这个值系统会帮你随机生成,就相当于让面的ross_domain#} {# 当拿到结果之后,只会执行function ()这个匿名函数#} console.log(data) }) }) </script>
项目二后端部分:
import json def ajax_send(request): dict = {"name":"kebi"} func =request.GET.get("callback") print("func",func) #func jQuery3210924015436172589_1519900847362 print("项目2.。。") return HttpResponse("%s(%s)"%(func,json.dumps(dict)))
经过测试可以知道,这种方法也是可以的,其实就是对script的封装。
结果是一样的,要注意的是在url的后面必须添加一个callback参数,这样getJSON方法才会知道是用JSONP方式去访问服务,
callback后面的那个问号是内部自动生成的一个回调函数名。
此外,如果说我们想指定自己的回调函数名,或者说服务上规定了固定回调函数名该怎么办呢?我们可以使用$.ajax方法来实现
(2)$.ajax
看到这个有些人就疑惑,这个不就是Ajax吗,不是说ajax不行吗,这咋就又行了?
其实确实不行,只是Jquery的作者让它和ajax同名而已。
项目一前端:
<script> $(".b1").click(function () { $.ajax({ url:'http://127.0.0.1:8002/ajax_send/', dataType:"jsonp", {# 期待数据类型,一定要加,只要有这句话,就会去添加script标签 #} jsonp: 'callback', {# 其实就是补充在后面:http://127.0.0.1:8002/ajax_send/?callback=SayHi#} jsonpCallback:"SayHi" {# 如果这里不加jsonpCallback,就会是callback=?,这样就是getJson #} }); }); function SayHi(data) { console.log(data) } </script>
项目二后端:
def ajax_send(request): dict = {"name":"kebi"} func =request.GET.get("callback") print("func",func) #func SayHi print("项目2.。。") return HttpResponse("%s(%s)"%(func,json.dumps(dict)))
当然,最简单的形式还是通过回调函数来处理(推荐):
<script> $(".b1").click(function () { $.ajax({ url:'http://127.0.0.1:8002/ajax_send/', dataType:"jsonp", jsonp: 'callback', success:function (data) { console.log(data) } }); }); </script>
jsonp: 'callbacks'就是定义一个存放回调函数的键,jsonpCallback是前端定义好的回调函数方法名'SayHi',
server端接受callback键对应值后就可以在其中填充数据打包返回了;
jsonpCallback参数可以不定义,jquery会自动定义一个随机名发过去,那前端就得用回调函数来处理对应数据了。
利用jQuery可以很方便的实现JSONP来进行跨域访问。
注意:JSONP一定是GET请求
最后来一个跨域请求的实例:
<input type="button" onclick="AjaxRequest()" value="跨域Ajax" /> <div id="container"></div> <script type="text/javascript"> function AjaxRequest() { $.ajax({ url: 'http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403', type: 'GET', dataType: 'jsonp', jsonp: 'callback', jsonpCallback: 'list', success: function (data) { $.each(data.data,function(i){ {# 循环 #} var item = data.data[i]; var str = "<p>"+ item.week +"</p>"; {# 添加日期标签 #} $('#container').append(str); $.each(item.list,function(j){ {# 循环 #} var temp = "<a href='http://t.zoukankan.com/" + item.list[j].link +"'>" + item.list[j].name +" </a><br/>"; $('#container').append(temp); }); $('#container').append("<hr/>"); }) } }); } </script>