day24-JSONP跨域请求本质
一、前言
我们之前访问的接口或者url 都是在自己本网站去访问,或者 提交 ,但是如果我要去调第三方接口,那怎么办,或者说我去调 其他 网站的接口,在我自己的网站去返回,这边就存在 跨域访问 ,这边是有限制的,所以,我们如何解决这个问题呢?我们比如说用 requests 这个模块去访问 接口的时候,会返回在 自己的web上:
from django.shortcuts import render import requests # pip install requests # Create your views here. def req(request): response = requests.get("http://weatherapi.market.xiaomi.com/wtr-v2/weather?cityId=101121301") #返回的是一个字节 # print(response.text) #文本,这边把字节给转换了 # print(response.cookies) # cookie # print(response.headers) # response_header response.encoding = "utf-8" #设置response变成utf-8变成字符串 return render(request,'req.html',{'result': response.text})
原理图如下:
说明这种方式是可以访问的,但是如果我们想要通过ajax 的形式跨域形式去访问呐,接下来我们就来讨论讨论。
二、JSONP存在的原因和原理
2.1、存在的原因
由于浏览器具有同源(源指的是第三方域名)策略,你如果取别的域名请求,我浏览器直接就会给你阻止掉了,比如我们用 ajax 请求 第三方接口的话,就相当于直接阻止了 ajax的请求(Failed to load http://weatherapi.market.xiaomi.com/wtr-v2/weather?cityId=101121301: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.),但是无法阻止 含有src 属性标签的(<script crc='....'></script>),就是说所有含有src属性的标签,都不受到同源策略的影响。
2.2、实现jsonp的形式的条件
我们实现jsonp的形式的条件:
- 创建script 标签
- scr = 远程地址
- 返回的数据类型必须是js格式
只能发GET请求,不能是POST请求,就算是POST请求的话,也会转成GET请求的。
2.3、原理图
三、前提
由于我们方便测试jsonp跨域,所以我们这边自己再另外建立一个 django project 项目,来模拟 第三方页面请求,所以我们新建的项目,并且设置本地hosts。操作步骤如下:
3.1、路由设置(urls.py)
说明:模拟第三方页面的url设置
from django.urls import path from app01.views import accounts urlpatterns = [ path('jsonp.html/',accounts.jsonp), ]
3.2、jsonp函数编写
说明:模拟第三方页面的函数编写
from django.shortcuts import HttpResponse def jsonp(request): """ 测试jsonp的请求接口 :param request: :return: """ print(request.GET) return HttpResponse('alert(1000)')
3.3、添加 hosts
说明:这个可以用本地hosts添加绑定域名
127.0.0.1 zhangqigao.com
3.4、需要添加白名单
说明:通过域名访问模拟第三方页面,需要在第三方项目 settings.py文件中添加白名单
ALLOWED_HOSTS = ['zhangqigao.com','127.0.0.1',] # add white name table
四、JSONP请求跨域
我们创建本地项目,然后我们这边有些东西是不变的,比如url和函数,修改的只是模板,因为只是通过 原生ajax 或者 添加标签方式,或者用 jquery的方式去访问,所以我这边的url 和 req函数我就直接写了
4.0、前提
路由设置(url):
from django.urls import path from app02 import views as a2 urlpatterns = [ path('req/',a2.req) ]
req函数:
def req(request): return render(request,'req.html')
4.1、原生ajax跨域请求
说明:我们知道原生ajax调第三方接口的时候,去自己的浏览器去显示的时候,本地浏览器是拒绝的,并且会给你一个拒绝的提示,因为它受到同源策略的影响,这边就直接写 req.html就行了
<body> <input type="button" value="获取数据" onclick="getContent();"> <script> function getContent() { var xhr = new XMLHttpRequest(); //xhr.open('GET','http://weatherapi.market.xiaomi.com/wtr-v2/weather?cityId=101121301'); //天气接口 xhr.open('GET', 'http://zhangqigao.com:8080/jsonp.html?k1=v1&k2=v2'); //模拟第三方接口,这边通过get传入 k1和k2 xhr.onreadystatechange = function () { console.log(xhr.responseText); }; xhr.send(); </script> </body>
我们来看一下效果,正是因为受到同源策略的影响,所以我们在接收请求的时候,浏览器是拒绝的,拒绝的效果图如下:
4.2、创建script标签方式跨域请求
说明:我们知道所有带src属性的标签都不收同源策略的影响,所以我们通过这种方式来看一下,看一下这种方式是怎么实现的。
<body> <!-- <h1>后台获取的结果</h1> {{ result }} <h1>js直接获取结果</h1> --> <input type="button" value="获取数据" onclick="getContent();"> <script> function getContent() { var tag = document.createElement('script'); tag.src = "http://zhangqigao.com:8080/jsonp.html?callback=list&k2=v2"; //请求模拟第三方页面 document.head.appendChild(tag); } </script> </body>
我们现在看看能不能接受到请求过来的参数,因为我们说,这边只接收 js形式的,所以是字符串形式的我们就不测试了,所以我们下面来看看:
我靠,这边确实没有收到同源策略的影响,但是我们这边只接收了一个alert,那我如果接收一个callback函数,并且定义传过来的函数不就行了,那我的模拟第三方的jsonp函数代码如下:
from django.shortcuts import HttpResponse def jsonp(request): """ 测试jsonp的请求接口 :param request: :return: """ print(request.GET) # return HttpResponse('alert(1000)') # return HttpResponse('callbakc(1000)') func = request.GET.get('callback') #callback = list content = '%s(1000)'%(func,) # list(1000) return HttpResponse(content) # 返回 content=list(1000)
我的本地的req.html改进:
<body> <input type="button" value="获取数据" onclick="getContent();"> <script> var tag = document.createElement('script'); tag.src = "http://zhangqigao.com:8080/jsonp.html?callback=list&k2=v2"; //一般情况传入的都叫callback //tag.src = "http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403"; //这个是某个天气的接口,这个可以测试,是一样的 document.head.appendChild(tag); document.head.removeChild(tag); //不能无限的添加,只要我把值传过来,我就立马删掉就行了 } function list(args){ //通过callback=list参数,如果不写的话,浏览器会报 list is not defind,所以要定义 list函数 console.log(args); //args就是接收第三方的list(1000)中1000这参数,也就是说这边 args = 1000 } </script> </body>
实现的效果图:
tag.src = "http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403"; //这个是某个天气的接口,这个可以测试,是一样的,这边测试一下结果:
4.3、Jquery跨域请求方式
说明:jquery的跨域的本质原理跟上面 通过创建 script是一样的,我们用的时候首选用jquery这种方式,也是快速加一个script标签,然后又把新增的script的标签删掉。
<body> <!-- <h1>后台获取的结果</h1> {{ result }} <h1>js直接获取结果</h1> --> <input type="button" value="获取数据" onclick="getContent();"> <script src="/static/jquery-1.12.4.js"></script> <script> function getContent() { $.ajax({ url:'http://www.jxntv.cn/data/jmd-jxtv2.html?_=1454376870403', type: 'GET', //这边写POST也行,反正是最后还是要转成GET的,我们这边就直接写成GET dataType: 'jsonp', jsonp:'callback', jsonCallback:'list' //jsonp和jsonCallback合起来表示:http://url?callback=list的效果 }) } function list(args){ console.log(args); } </script> </body>
测试过了,跟上面的效果是一模一样啊,这个就是jquery请求方式。更多跨域方式:http://www.cnblogs.com/wupeiqi/articles/5369773.html 3.文档处理->6.ajax 跨域
4.4、cors
说明:这个东西不是经常用,常用的还是我们上面的通过jquery的方式,但是我们知道有这么一个东西,随着技术的发展,现在的浏览器可以支持主动设置从而允许跨域请求,即:跨域资源共享(CORS,Cross-Origin Resource Sharing),其本质是设置响应头,使得浏览器允许跨域请求。
更多详细资料:https://www.cnblogs.com/wupeiqi/articles/5703697.html 中的 跨域ajax
五、总结
1、jsonp跨域请求方式 只能是 GET 方法 就算是POST方法也会转成GET方法
2、我们实现jsonp的形式的条件:
- 创建script 标签
- scr = 远程地址
- 返回的数据类型必须是js格式
3、跨域还可以用jquery的方式,当然还可以是 cors,只是我们用的最多的是 jquery方式 ,但是原理还是 第2种