首页 > 技术文章 > 白话之jsonp跨域原理分析

jimmyhe 2019-05-12 15:43 原文

  一、针对跨域请求,我们首先要知道什么是同源策略。

  同源策略即是指:域名,协议,端口相同,三者中有一者不一致,为了安全考虑我们所在的服务器是无法获得想要访问资源所在服务器的资源的。

  如图:

  比如我们在localhost:9090/result上有json数据:data = {'name':'jack','age':24},我们在localhost:8080中定义了一个事件功能去获取数据:

<html>
<head>
     <title>跨域测试</title>
     <script src="js/jquery-1.7.2.js"></script>
     <script>
         $(document).ready(function () {
             
             $("#btn").click(function () {
                 $.ajax({
                     url: 'http://localhost:9090/student',
                     type: 'GET',
                     success: function (data) {
                         $(text).val(data);
                     }
                 });
 
             });
             
         });
     </script>
 </head>
 <body>
    <input id="btn" type="button" value="跨域获取数据" />
    <textarea id="text" style="width: 400px; height: 100px;"></textarea>
</body>
</html>

  请求会失败如下:

  二、为了跨域访问资源,我们看一下jsonp的原理

  我们知道网站上的图片我们可以通过<img src='xxxx'>来获取,其实是可以直接通过src跨域请求的。同样,我们可以利用src来访问外部服务器的资源:

  

 2 <html>
 3 <head>
 4     <title>跨域测试</title>
 5     <script src="js/jquery-1.7.2.js"></script>
 6     <script>
 7         //回调函数
 8         function showData (result) {
 9             var data = JSON.stringify(result); //json对象转成字符串
10             $("#text").val(data);
11         }
12 
13         $(document).ready(function () {
14 
15             $("#btn").click(function () {
16                 //向头部输入一个脚本,该脚本发起一个跨域请求
17                 $("head").append("<script src='http://localhost:9090/student?callback=showData'><\/script>");
18             });
19 
20         });
21     </script>
22 </head>
23 <body>
24     <input id="btn" type="button" value="跨域获取数据" />
25     <textarea id="text" style="width: 400px; height: 100px;"></textarea>
26 
27 </body>
28 </html>

后端处理:

def get_data(request):
  
  func = request.GET.get('showData')

  if func:
    data = func() # 这里我们可以将数据由这个func函数取出来

    return data

  else:

  return

这样可以绕过同源策略的限制取到数据,接下来我们用jsonp方式而不是构造src标签,同样我们服务端后台的逻辑不变,改变前端的请求方式:

最简单的方式,只需配置一个dataType:'jsonp',就可以发起一个跨域请求。jsonp指定服务器返回的数据类型为jsonp格式,可以看发起的请求路径,自动带了一个callback=xxx,xxx是jquery随机生成的一个回调函数名称。

2 <html>
 3 <head>
 4     <title>跨域测试</title>
 5     <script src="js/jquery-1.7.2.js"></script>
 6     <script>
 7 
 8         $(document).ready(function () {
 9 
10             $("#btn").click(function () {
11 
12                 $.ajax({
13                     url: "http://localhost:9090/student",
14                     type: "GET",
15                     dataType: "jsonp", //指定服务器返回的数据类型
              jsonpCallback:"showData" //指定函数名
16 success: function (data) { 17 var result = JSON.stringify(data); //json对象转成字符串 18 $("#text").val(result); 19 } 20 }); 21 22 }); 23 24 }); 25 </script> 26 </head> 27 <body> 28 <input id="btn" type="button" value="跨域获取数据" /> 29 <textarea id="text" style="width: 400px; height: 100px;"></textarea> 30 31 </body> 32 </html>

跟之前构造src不同的是:1.我们ajax请求的url中并没有拼接函数名称。2.ajax中datatype指定为jsonp。3.制定了jsonpCallback名。

同样可以完成跨域的数据传输,在jquery源码中,jsonp调用回调函数是,调用的是window.callback, 会将jsonp指定的函数名进行调用,再返回函数结果。

 

  三、post请求jsonp方式是否可以呢?

  我们将ajax的请求方式由get改为post,后端也做相应的处理,可以看到效果:

可以看到浏览器会将我们的post请求自动转为get请求,其实jquery的jsonp就是将我们把<script>做了一层封装,内部还是只能用get方法去获取数据。

 

总结:1. 我们构造script标签的方式可以获取外部服务器的资源,jquery本身也是对我们这一层操作做了一层封装。

   2.jsonp只支持GET方式去访问外部服务器。

   3.jsonp和我们所访问的服务器必须用统一个函数名称来返回数据,jsonp发送了一个函数名,将此传给后端,后端才知道具体执行什么函数返回结果。

 

推荐阅读