zoukankan      html  css  js  c++  java
  • JSONP浅析

    为什么使用JSONP

    JSONP和JSON是不一样的。JSON是一种基于文本的数据交换方式,或者叫做数据描述格式。而JSONP是一种方式或者说非强制性协议。它是为了解决某个难题而产生的一种技术方式。

    为什么会用到JSONP呢?

    我们平时在用ajax请求服务端数据时,一般是这么写的:

    $.ajax({     type: "get",     url: "getData.php",     dataType: "json",     success: function (data, textStatus, jqXHR) {         console.log(data);     },     error: function (XMLHttpRequest, textStatus, errorThrown) {         alert('fail');     } });

    这是一段很普通的基于jQuery的AJAX请求,不会有什么问题。注意到:url里是getData.php,说明这个文件url是基于当前服务器的,例如可能是localhost,也就是前端发出的请求来源是localhost,后端肯定也是localhost。他们俩是在同一个域名下。当然,平时我们也不会特别注意。

    这时候,假如这个url变成其它服务器上的地址,例如:'http://apis.juhe.cn/mobile/get?phone=13429667914&key=',我们再把请求发送出去,会发现出问题了。大家可以手动写个示例看看。

    DEMO: 为什么使用jsonp?

    出什么问题了?被限制请求了!

    XMLHttpRequest cannot load http://apis.juhe.cn/mobile/get?phone=13429667914&key=. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://demo.52fhy.com' is therefore not allowed access.

    也就是请求来源与服务器不是同一个域名,不允许访问。这就是浏览器同源策略

    所谓"同源"指的是"三个相同":  协议相同 域名相同 端口相同  举例来说,http://www.example.com/dir/page.html这个网址,协议是http://,域名是www.example.com,端口是80(默认端口可以省略)。它的同源情况如下。 http://www.example.com/dir2/other.html:同源 http://example.com/dir/other.html:不同源(域名不同) http://v2.www.example.com/dir/other.html:不同源(域名不同) http://www.example.com:81/dir/other.html:不同源(端口不同)

    同源政策规定,AJAX请求只能发给同源的网址,否则就报错。

    那么,这时候该怎么办呢?我就是想通过js请求对方服务器上的资源!

    除了架设服务器代理(浏览器请求同源服务器,再由后者请求外部服务),有三种方法规避这个限制。

    • JSONP
    • WebSocket
    • CORS

    本文只对JSONP作介绍。

    如何使用JSONP

    首先前端这边代码得改改,假设先不用jQuery:

    <script type="text/javascript"> //跨域发送HTTP请求,从服务端获取数据,callback指定回调函数名称 var url = 'http://demo.52fhy.com/jsonp/handJsonp.php?callback=handler';  function getHello() {     var script = document.createElement('script');     script.setAttribute('src', url);     document.querySelector("head").appendChild(script); } // 处理函数 function handler(data) {     console.log(data);     // our code here... } </script>  <input type="button" value="发送跨域HTTP请求,获取数据" onclick="getHello()" />

    后端服务器也要改改。

    例如,在PHP语言中,后端服务器在API里返回JSON数据,一般是这么写的:

    $data = array('name' => '52fhy', 'age' => '22'); echo json_encode($data); exit;

    这里需要改成:

    $data = array('name' => '52fhy', 'age' => '22'); handJsonp($data);  //处理jsonp function handJsonp($data){     $callback = $_GET['callback'] ? : 'callback'; //默认使用callback     echo sprintf("%s(%s)", $callback, json_encode($data));     exit; }

    一旦请求成功,服务端输出了:

    handler({name: "52fhy", age: "22"});

    这时候浏览器就要响应了,找到handler()方法并执行,恰好,我们提前定义好了handler()方法。

    这里为什么服务端没有限制访问呢?原因是我们通过动态添加了个:

    <script src="http://demo.52fhy.com/jsonp/handJsonp.php?callback=handler"></script>

    它的基本思想是,网页通过添加一个<script>元素,向服务器请求JSON数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。

    这种方法就是JSONP。

    使用jQuery/Zepto

    如果使用jQuery/Zepto,JSONP的方式将会和发送非跨域请求那样简单。
    示例:

    $.ajax({     type: "get",     async: false,     url: "http://demo.52fhy.com/jsonp/handJsonp.php",     dataType: "jsonp",     success: function (data, textStatus, jqXHR) {         console.log(data);     },     error: function (XMLHttpRequest, textStatus, errorThrown) {         alert('fail');         console.log(XMLHttpRequest, textStatus, errorThrown);     } });

    只需要将dataType设置成jsonp就可以进行跨域请求了。在success里我们能接收到来自服务端的响应:

    {name: "52fhy", age: "22"}

    DEMO: Zepto jsonp demo

    通过console控制台,可以看到请求信息:

    Request URL:http://demo.52fhy.com/jsonp/handJsonp.php?_=1460899828609&callback=jsonp1 Request Method:GET Status Code:200 OK

    jQuery/Zepto为我们封装好了回调函数,一般情况下不需要我们单独去写,如果你不想在success中处理,想单独写处理函数,那么可以通过设置这2个参数来实现:

    jsonp: "callback",//传递给服务端的回调函数名称参数,如果不设置此项,则默认是"callback"  jsonpCallback: "handler",//传递给服务端的回调函数名称,如果不设置此项,jQuery默认是形如"jQuery18308539637457579374_1460898291266"的由jQuery自动生成的函数名称,Zepto默认是`jsonp1`

    如果是zepto,可以在success回调里面使用console.log(jsonp1),发现jsonp1()方法是存在的。

    需要注意的是:

    1.JSONP虽然看起来很像一般的ajax请求,但其原理不同,JSONP是通过<script>标签的动态加载来实现的跨域请求,而一般的ajax请求是通过XMLHttpRequest对象进行;
    2.JSONP不是一种标准协议,其安全性和稳定性都不如 W3C 推荐的 CORS;
    3.JSONP不支持POST请求,即使把请求类型设置为post,其本质上仍然是一个get请求。

    参考

    1、浏览器同源政策及其规避方法 - 阮一峰的网络日志
    http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html
    2、跨域资源共享 CORS 详解 - 阮一峰的网络日志
    http://www.ruanyifeng.com/blog/2016/04/cors.html
    3、说说JSON和JSONP,也许你会豁然开朗_知识库_博客园
    http://kb.cnblogs.com/page/139725/
    4、跨域解决方案二:使用JSONP实现跨域 - choon - 博客园
    http://www.cnblogs.com/choon/p/5393682.html
    5、JSON-P: Safer cross-domain Ajax with JSON-P/JSONP
    http://json-p.org/

    这个人不懒,写了一点东西
  • 相关阅读:
    Java实现 蓝桥杯VIP 算法训练 一元三次方程
    Java实现 蓝桥杯VIP 算法训练 乘法表
    Java实现 蓝桥杯VIP 算法训练 矩阵加法
    Java实现 蓝桥杯VIP 算法训练 一元三次方程
    Java实现 蓝桥杯VIP 算法训练 平方计算
    Java实现 蓝桥杯VIP 算法训练 平方计算
    Java实现 蓝桥杯VIP 算法训练 平方计算
    Java实现 蓝桥杯VIP 算法训练 乘法表
    Java实现 蓝桥杯VIP 算法训练 乘法表
    监管只是压倒网盘业务的一根稻草,但不是主要原因(答案只有一个:成本!)
  • 原文地址:https://www.cnblogs.com/AnonymouL/p/5403220.html
Copyright © 2011-2022 走看看