jsonp 跨域原理分析

本篇文章借鉴自 博客园文章

原文地址

AJAX即“Asynchronous Javascript And XML”(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术。

AJAX 的出现使得网页可以通过在后台与服务器进行少量数据交换,实现网页的局部刷新。

但是出于安全的考虑,ajax不允许跨域通信(浏览器同源策略)。
如果尝试从不同的域请求数据,就会出现错误(跨域错误)。
在实际开发中,往往需要进行跨于请求,这时要怎么办呢?

关于ajax跨域请求?

1、Ajax为什么不能跨域?到底是卡在哪个环节了?。 (请求成功了,但客户端浏览器拿不到请求结果)

Ajax其实就是向服务器发送一个GET或POST请求,然后取得服务器响应结果,返回客户端。

理论上这是没有任何问题的,然而普通ajax跨域请求,在服务器端不会有任何问题,只是服务端响应数据返回给浏览器的时候,

浏览器根据响应头的Access-Control-Allow-Origin字段的值来判断是否有权限获取数据,

一般情况下,服务器端如果没有在这个字段做特殊处理的话,跨域是没有权限访问的,所以响应数据被浏览器给拦截了,

所以在ajax回调函数里是获取不到数据的。所以现在ajax跨域的问题可以转化为数据怎么拿回客户端的问题。

2、 html的script标签,img标签,iframe标签,可以请求第三方的资源(不受同源策略影响)

web页面可以加载放在任意站点的js、css、图片等资源,不会受到"跨域"的影响。

这个时候,我们会想到:既然我们可以调用第三方站点的js,那么如果我们将数据放到第三方站点的js中不就可以将数据带到客户端了吗?

JSONP

1、什么是JSONP?

JSONP(JSON with Padding(填充))是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。

其核心思想是利用JS标签里面的跨域特性进行跨域数据访问,
在JS标签里面存在的是一个跨域的URL,实际执行的时候通过这个URL获得一段字符串,
这段返回的字符串必须是一个合法的JS调用,通过EVAL这个字符串来完成对获得的数据的处理。

即: <script src='url'></script>

JSONP是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,
通过javascript callback的形式实现跨域访问(这仅仅是JSONP简单的实现形式)。

2、JSONP的粗糙实现

下面我们通过一个例子来说明一下JSONP是如何实现ajax跨域请求的。

html 代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div>jsonp</div>
</body>
<script>
    function getremotedata(data) {
        console.log(data);
    }
    var div = document.getElementsByTagName('div');

    div[0].onclick = function(){
        var url = "./getdata.js";
        var script = document.createElement('script');
        script.setAttribute('src',url);
        document.getElementsByTagName('head')[0].appendChild(script);
    };
</script>
</html>

远程的getdata.js

getremotedata({
    code:0,result:'success'
});

得到的结果:

jsonp前端及后台php的写法

html代码还是和上面一样,只要改变 url就可以了
url= 'localhsot:8080/search.php?callback=getremotedata'

后台 php 代码
<?php
    $callback = $_GET['callback'];

    if($callback == 'getremotedata' ){
        echo $_GET['$callback']).'('. json_encode({code:0,msg:"success"}) .')';
    }
    ?>

看到这里清楚了吧,就是第三方站点生成一个对回调函数的调用,传入查询结果,
然后通过 <script> 加载到客户端执行

下图是 jsonp请求的流程图

jquery 封装在 ajax方法 里面的jsonp

jquery 是如何把 jsonp 封装到ajax里面的?

<script type="text/javascript">
    function GetAjaxData() {
        $.ajax({
            type: "get",async: false,url: "http://localhost:8080/getdata.php",dataType: "jsonp",jsonp: "callback",//传递给请求处理程序或页面的,标识jsonp回调函数名(一般为:callback)
            jsonpCallback: "GetData",//callback的function名称
            success: function (data) {
                console.log(data);
            },error: function () {
                alert('fail');
            }
        });
    }
</script>

一般情况下jqury 生成的访问 远程站点的 url
默认情况下:(我所在的实际项目中的使用)

http://web.k3k.net/haila3/pt/tp/index.php/Home/User/getusergoto/?callback=jQuery191028614189839964865_1497261919344&token=420171c8-031a58667e64&_=1497261919346

上述代码请求生成的url(设置 jsonpCallback的值为 GetData

http://web.k3k.net/haila3/pt/tp/index.php/Home/User/getusergoto/?callback=GetData&token=420171c8-00b8-031a58667e64&_=1497261919346

最后 一个 _=1497261919346 k v 是为了防止浏览器缓存,而由 jquery 自动增加上的。

所以相当于 在 前端文件中引入了 一个这样的js文件

<script src="http://web.k3k.net/haila3/pt/tp/index.php/Home/User/getusergoto/?callback=GetData&token=420171c8-00b8-031a58667e64&_=1497261919346"></script>

这里有2个重要的参数

jsonp
在一个jsonp请求中重写回调函数的名字。这个值用来替代在"callback=?"这种GET或POST请求中URL参数里的"callback"部分,
比如{jsonp:'onJsonPLoad'}会导致将"onJsonPLoad=?"传给服务器。

jsonpCallback
为jsonp请求指定一个回调函数名。这个值将用来取代jQuery自动生成的随机函数名。
这主要用来让jQuery生成一个独特的函数名,这样管理请求更容易,也能方便地提供回调函数和错误处理。

你也可以在想让浏览器缓存GET请求的时候,指定这个回调函数名。

从jQuery 1.5开始,你也可以使用一个函数作为该参数设置,在这种情况下,该函数的返回值就是jsonpCallback的结果。

通过一开始 jsonp 原理的分析,可以得出:

当我们正常地请求一个JSON数据的时候,服务端返回的是一串JSON类型的数据。
而我们使用JSONP模式来请求数据的时候,服务端返回的是一段可执行的JavaScript代码

所以我们可见服务器代码最后一行

echo $_GET['$callback']).'('. json_encode({code:0,msg:"success"}) .')';

就是执行的 getdata,然后把数据通过回调的方式传递过去

OK,就是整个流程就是:

客户端发送一个请求,规定一个可执行的函数名
(这里就是jQuery做了封装的处理,自动帮你生成回调函数并把数据取出来供success属性方法来调用,不是传递的一个回调句柄),
服务端接受了这个 getdata 函数名,然后把数据通过实参的形式发送出去

以上是 jquery 封装的 ajax方法里面的 jsonp 请求,说来说去,自己都好像忘记了普通的 ajax请求

js原生 ajax 请求
//1.创建对象
        var ajax = '';

        if(window.XMLHttpRequest){
            ajax = new XMLHttpRequest();    /* 现代浏览器 */
        }else if(window.ActiveXObject){
            ajax = new ActiveXObject("Microsoft.XMLHTTP");  /* 万恶的ie浏览器 */
        }

        //2.创建请求

        //get请求方法(拼接url参数)
//      var url="login.php?name="+name+"&password="+pass;
//      ajax.open("GET",url,true);

        //post请求
        ajax.open("POST","login.php",true);
        ajax.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
        var data="name="+name+"&password="+pass;

        //3.发送请求
//      ajax.send();        //get 方式发送请求
        ajax.send(data);    //post 方式发送请求

        //4.捕获请求状态、onreadystatechange表示当前请求状态

        ajax.onreadystatechange=function(){
            //5.判断请求状态
            if(ajax.readyState==4){
                //6.判断请求结果
                if(ajax.status==200){
                    //请求成功将结果 responseText 放入回调函数中
                    succ(ajax.responseText);
                }
            }
        }

注意

通过检测window对象是否有XMLHttpRequest属性来确定浏览器是否支持标准的XMLHttpRequest。
注意,不要根据浏览器的navigator.userAgent来检测浏览器是否支持某个JavaScript特性,一是因为这个字符串本身可以伪造,二是通过IE版本判断JavaScript特性将非常复杂。

当创建了XMLHttpRequest对象后,要先设置onreadystatechange的回调函数。在回调函数中,通常我们只需通过readyState === 4判断请求是否完成,
如果已完成,再根据status === 200判断是否是一个成功的响应。

XMLHttpRequest对象的open()方法有3个参数,
第一个参数指定是GET还是POST,
第二个参数指定URL地址,
第三个参数指定是否使用异步,默认是true,所以不用写。

注意,千万不要把第三个参数指定为false,否则浏览器将停止响应,直到AJAX请求完成。
如果这个请求耗时10秒,那么10秒内你会发现浏览器处于“假死”状态。

最后调用send()方法才真正发送请求。
GET请求不需要参数,
POST请求需要把body部分以字符串或者FormData对象传进去。

jquery实现普通ajax

<script type="text/javascript">
    $("#btn").on("click",function(){
        var name=$("#name").val();
        var pass=$("#password").val();

        $.ajax({
            type:"post",url:"login&jq.php",async:true,//异步简写
            dataType:"json",//转化为json类型
            data:{
                name:name,password:pass,},success:function(data){
                console.log(data);
            },error:function(data){
                alert(data);
            }
        });
    })
    </script>

后台 php 代码

<?php
    include_once "common.php";
    $name=$_POST["name"];
    $password=$_POST["password"];

    $sql="select*from user where name='$name' and password= '$password'";

    $result=mysql_query($sql);

    if(mysql_num_rows($result)==1){
        $row = mysql_fetch_assoc($result);
        //只能传一个json
        echo json_encode($row);
    }else{
        //只能用json
        echo '{"msg":"输入有误"}';
    }

?>

当然实现跨域的方法还有很多,html5规范 的 CORS(全称Cross-Origin Resource Sharing),是HTML5规范定义的如何跨域访问资源。

了解CORS前,我们先搞明白概念:
Origin表示本域,也就是浏览器当前页面的域。当JavaScript向外域(如sina.com)
发起请求后,浏览器收到响应后,首先检查Access-Control-Allow-Origin是否包含本域,
如果是,则此次跨域请求成功,如果不是,则请求失败,JavaScript将无法获取到响应的任何数据。

假设本域是my.com,外域是sina.com,只要响应头Access-Control-Allow-Origin为http://my.com,或者是*,本次请求就可以成功。

可见,跨域能否成功,取决于对方服务器是否愿意给你设置一个正确的Access-Control-Allow-Origin,决定权始终在对方手中。

总结

1、ajax和jsonp这两种技术在调用方式上“看起来”很像,目的也一样,都是请求一个url,然后把服务器返回的数据进行处理,因此jquery和ext等框架都把jsonp作为ajax的一种形式进行了封装;

2、ajax和jsonp其实本质上是不同的东西。ajax的核心是通过XMLHttpRequest获取非本页内容,而jsonp的核心则是通过HTTP来动态添加 <script> 标签来调用服务器提供的js脚本。

3、其实ajax与jsonp的区别不在于是否跨域,ajax通过服务端代理(CORS)一样可以实现跨域,jsonp本身也不排斥同域的数据的获取。

4、jsonp是一种方式或者说非强制性协议,如同ajax一样,它也不一定非要用json格式来传递数据,如果你愿意,字符串都行,只不过这样不利于用jsonp提供公开服务。

5、jsonp整个过程中,本地站点一直处于主动的地位,主动的发送请求,主动的加载远程js.而第三方站点则处于被动的响应。

josnp 优缺点分析: 借鉴自w3cfun

优点:

1.1它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制,JSONP可以跨越同源策略;
    
1.2它的兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持;
    
1.3在请求完毕后可以通过调用callback的方式回传结果。
将回调方法的权限给了调用方。这个就相当于将controller层和view层终于分开了。
我提供的jsonp服务只提供纯服务的数据,至于提供服务以 后的页面渲染和后续view操作都由调用者来自己定义就好了。
如果有两个页面需要渲染同一份数据,你们只需要有不同的渲染逻辑就可以了,
逻辑都可以使用同 一个jsonp服务。

缺点

2.1它只支持GET请求而不支持POST等其它类型的HTTP请求

2.2它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。

2.3 jsonp在调用失败的时候不会返回各种HTTP状态码。

2.4缺点是安全性。万一假如提供jsonp的服务存在页面注入漏洞,即它返回的javascript的内容被人控制的。
那么结果是什么?所有调用这个 jsonp的网站都会存在漏洞。
于是无法把危险控制在一个域名下…所以在使用jsonp的时候必须要保证使用的jsonp服务必须是安全可信的。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


文章浏览阅读2.4k次。最近要优化cesium里的热力图效果,浏览了网络上的各种方法,发现大多是贴在影像上的。这么做好是好,但是会被自生添加的模型或者其他数据给遮盖。其次是网上的方法大多数是截取成一个矩形。不能自定义的截取自己所需要的。经过尝试,决定修改下cesium heatmap,让他达到我们需要的要求。首先先下载 cesium heatmap包。其中我们可以看到也是通过叠加entity达到添加canvas的方法绘制到地图上。我们先把这一段代码注释} else {} };
文章浏览阅读1.2w次,点赞3次,收藏19次。在 Python中读取 json文件也可以使用 sort ()函数,在这里我介绍一个简单的示例程序: (4)如果我们想将字符串转换为列表形式,只需要添加一个变量来存储需要转换的字符串即可。在上面的代码中,我们创建了一个名为` read`的对象,然后在文件的开头使用`./`关键字来命名该对象,并在文件中定义了一个名为` json`的变量,并在其中定义了一个名为` json`的字段。比如,我们可以使用 read方法读取 json文件中的内容,然后使用 send方法将其发送到 json文件中。_python怎么读取json文件
文章浏览阅读1.4k次。首字母缩略词 API 代表应用程序编程接口,它是一种设备,例如用于使用编程代码发送和检索数据的服务器。最常见的是,该技术用于从源检索数据并将其显示给软件应用程序及其用户。当您访问网页时,API 的工作方式与浏览器相同,信息请求会发送到服务器,如何在 Windows PC 中手动创建系统还原点服务器会做出响应。唯一的区别是服务器响应的数据类型,对于 API,数据是 JSON 类型。JSON 代表 JavaScript Object Notation,它是大多数软件语言中 API 的标准数据表示法。_api是什么 python
文章浏览阅读802次,点赞10次,收藏10次。解决一个JSON反序列化问题-空字符串变为空集合_cannot coerce empty string ("") to element of `java.util.arraylist
文章浏览阅读882次。Unity Json和Xml的序列化和反序列化_unity json反序列化存储换行
文章浏览阅读796次。reader.readAsText(data.file)中data.file的数据格式为。使用FileReader对象读取文件内容,最后将文件内容进行处理使用。_a-upload 同时支持文件和文件夹
文章浏览阅读775次,点赞19次,收藏10次。fastjson是由国内的阿里推出的一种json处理器,由java语言编写,无依赖,不需要引用额外的jar包,能直接运行在jdk环境中,它的解析速度是非常之快的,目前超过了所有json库。提示:以下是引用fastjson的方法,数据未涉及到私密信息。_解析器用fastjson还是jackson
文章浏览阅读940次。【Qt之JSON文件】QJsonDocument、QJsonObject、QJsonArray等类介绍及使用_使用什么方法检查qjsondocument是否为空
文章浏览阅读957次,点赞34次,收藏22次。主要内容原生 ajax重点重点JSON熟悉章节目标掌握原生 ajax掌握jQuery ajax掌握JSON第一节 ajax1. 什么是ajaxAJAX 全称为,表示异步的Java脚本和Xml文件,是一种异步刷新技术。2. 为什么要使用ajaxServlet进行网页的变更往往是通过请求转发或者是重定向来完成,这样的操作更新的是整个网页,如果我们只需要更新网页的局部内容,就需要使用到AJAX来处理了。因为只是更新局部内容,因此,Servlet。
文章浏览阅读1.4k次,点赞45次,收藏13次。主要介绍了JsonFormat与@DateTimeFormat注解实例解析,文中通过示例代码介绍的非常详细,对大家的学习 或者工作具有一定的参考学习价值,需要的朋友可以参考下 这篇文章主要介绍了从数据库获取时间传到前端进行展示的时候,我们有时候可能无法得到一个满意的时间格式的时间日期,在数据库中显 示的是正确的时间格式,获取出来却变成了时间戳,@JsonFormat注解很好的解决了这个问题,我们通过使用 @JsonFormat可以很好的解决:后台到前台时间格式保持一致的问题,
文章浏览阅读1k次。JsonDeserialize:json反序列化注解,作用于setter()方法,将json数据反序列化为java对象。可以理解为用在处理接收的数据上。_jsondeserialize
文章浏览阅读2.7k次。labelme标注的json文件是在数据标注时产生,不能直接应用于模型训练。各大目标检测训练平台或项目框架均有自己的数据格式要求,通常为voc、coco或yolo格式。由于yolov8项目比较火热,故此本博文详细介绍将json格式标注转化为yolo格式的过程及其代码。_labelme json 转 yolo
文章浏览阅读790次,点赞26次,收藏6次。GROUP_CONCAT_UNORDERED(): 与GROUP_CONCAT类似,但不保证结果的顺序。COUNT_DISTINCT_AND_ORDERED(): 计算指定列的不同值的数量,并保持结果的顺序。COUNT_ALL_DISTINCT(): 计算指定列的所有不同值的数量(包括NULL)。AVG_RANGE(): 计算指定列的最大值和最小值之间的差异的平均值。JSON_OBJECT(): 将结果集中的行转换为JSON对象。COUNT_DISTINCT(): 计算指定列的不同值的数量。_mysql json 聚合
文章浏览阅读1.2k次。ajax同步与异步,json-serve的安装与使用,node.js的下载_json-serve 与node版本
文章浏览阅读1.7k次。`.net core`提供了Json处理模块,在命名空间`System.Text.Json`中,下面通过顶级语句,对C#的Json功能进行讲解。_c# json
文章浏览阅读2.8k次。主要介绍了python对于json文件的读写操作内容_python读取json文件
文章浏览阅读770次。然而,有时候在处理包含中文字符的Json数据时会出现乱码的情况。本文将介绍一种解决Json中文乱码问题的常见方法,并提供相应的源代码和描述。而某些情况下,中文字符可能会被错误地编码或解码,导致乱码的出现。通过适当地控制编码和解码过程,我们可以有效地处理包含中文字符的Json数据,避免乱码的发生。通过控制编码和解码过程,我们可以确保Json数据中的中文字符能够正确地传输和解析。为了解决这个问题,我们可以使用C#的System.Text.Encoding类提供的方法进行编码和解码的控制。_c# json 中文编码
文章浏览阅读997次。【代码】【工具】XML和JSON互相转换。_xml 转json
文章浏览阅读1.1k次。json path 提取数据_jsonpath数组取值
文章浏览阅读3w次,点赞35次,收藏36次。本文主要介绍了pandas read_json时ValueError: Expected object or value的解决方案,希望能对学习python的同学们有所帮助。文章目录1. 问题描述2. 解决方案_valueerror: expected object or value