zoukankan      html  css  js  c++  java
  • JSON 与 JSONP

    JSON (JavaScript Object Notation) is a lightweight data-interchange format. 即 JSON 是一种轻量级的数据交换格式。

    1. JSON 的结构

    JSON 构建于于两种(除去简单值)结构(JSON is built on two structures) 

    对象名称(键) / 值对的集合(A collection of name / value pairs):

    {
      "key1": "value1",
      "key2": "value2"    
    }

    或者

    {
      "name": "dee",
      "age": 28,
      "stack": {
           "frontend": "JavaScript",
           "backend": "php" 
        }      
    }

    说明:

    一个对象以 { 开始,} 结束。每个名称(name)后跟一个 :

    每个键值对之间使用 , 分隔

    注意:JSON 对象属性里的非数字型键值必须要加双引号,不能不加或者加单引号

    数组值(value)的有序集合(An array is an ordered collection of values)

    类似于 JavaScript 中的数组:

    ["dee", 28, "developer"]

    把对象和数组结合起来,可以构建更复杂的数据集合:

    [
        {
            "title": "PHP Cookbook",
            "authors": [
                "Sklar",
                "Adam"
            ],
            "edition": 3
        },
        {
            "title": "Modern PHP",
            "authors": "Lockhart"
        }
    ]

    说明:

    一个数组以 [ 开始,] 结束。值之间使用 , 分隔。

    值(value)可以是字符串(string)、数值(number)、truefalse、 null、对象(object)或者数组(array)。这些结构可以嵌套。字符串类型的值必须双引号括起来

    2. JavaScript 解析和序列化 JSON

    解析:把 JSON 字符串转换为 JavaScript 对象

    序列化: 把Javascript 对象转换为 JSON 字符串

    JSON 流行的原因除了与 JavaScript 类似的语法,还有一个原因就是可以把 JSON 数据结构解析为 JavaScript 对象。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
        <script>
            // JavaScript 对象
            var book = [
            {
                "title": "PHP Cookbook",
                "authors": [
                    "Sklar",
                    "Adam"
                ],
                "edition": 3
            },
            {
                "title": "Modern PHP",
                "authors": "Lockhart"
            }
            ];
            console.log(book);
    
            // 把 JavaScript 序列化为 JSON 字符串 
            var jsonText = JSON.stringify(book);
            console.log(jsonText);
    
            // 把 JSON 字符串解析为 JavaScript 对象
            var bookCopy = JSON.parse(jsonText);
            console.log(bookCopy);
    
            // 旧版本浏览器使用 eval() 函数解析 JSON 字符串为 JavaScript 对象
            // 结果和使用 JSON.parse() 一样
            var bookCopy_ = eval(jsonText);
            console.log(bookCopy_);
    
        </script>
    </head>
    <body>
        
    </body>
    </html>

    结果如下(FireFox 44.0.2):

    3. jQuery 和 Ajax 获取与发送 JSON 

    ① 获取 JSON 数据

    客户端 json.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
        <script src="http://lib.sinaapp.com/js/jquery/1.9.1/jquery-1.9.1.min.js"></script>
        <script>
            $.ajax({
                url: "index.php",
                type: "post",
                dataType: "json", // 表明接收的返回值是 JSON 格式的 
                data: {
                    "name": "dee",
                    "job": "developer"
                },
                success: function(data) {
                    console.log(data);
                    $.each(data.stack, function(name, value) {
                        console.log(value);
                    });
                },
                error: function() {
                    console.log("error");
                }
            });
        </script>
    </head>
    <body>
        
    </body>
    </html>

    服务器端 index.php

    <?php
    
    if(isset($_POST['name']) && $_POST['name'] == 'dee') {
    
        $data['code'] = 200;
        $data['message'] = 'success';
        $data['stack']['frontend'] = ['html', 'css', 'javascript'];
        $data['stack']['backend'] = ['php', 'mysql', 'nosql', 'linux', 'node.js'];
    
        header('content-type:text/json');
        exit(json_encode($data));
    }

    输出:

    说明:在服务端写 API 接口的时候,如果是以 JSON 作为数据交换格式,要加上:

    header('content-type:text/json');

    此时接收到数据的客户端接受到的数据已经是一个 JavaScript 对象,不需要再做任何的解析工作,jQuery 已经自动把 JSON 字符串转换为了 JSON 对象。

    在客户端接收以 JSON 为数据交换格式的 API 接口返回的数据时,也要加上:

    dataType: "json",

    表明接收的返回值是 JSON 格式的。

    ② 发送 JSON 数据

    客户端 json2.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
        <script src="http://lib.sinaapp.com/js/jquery/1.9.1/jquery-1.9.1.min.js"></script>
    </head>
    <body>
        <form>
            <table>
                <tr>
                    <td>name:</td>
                    <td><input name="name" type="text"></td>
                </tr>
                <tr>
                    <td>job:</td>
                    <td><input type="text" name="job"></td>
                </tr>
                <tr>
                    <td clospan="2">
                        <input type="button" id="submit" value="submit">
                    </td>
                </tr>
            </table>
        </form>
    </body>
    <script>
        $('#submit').click(function(){
            $.ajax({
                url: "index2.php",
                type: "post",
                contentType: "application/json",
                data: JSON.stringify($('form').serializeArray()),
                dataType: "json",
                success: function(data) {
                    console.log(data);
                },
                error: function() {
                    console.log("error");
                }
            });
        });
    </script>
    </html>

    说明:

    把 contentType 设置为 application/json,即 JSON 的 MIME 类型,发送的数据的类型是 JSON 字符串,后端使用 PHP 处理请求时,需要从 php://input 里获得原始输入流,再 json_decode 成对象;

    serializeArray 会生成一个数组对象,每一个元素都表示一个表单 input 元素的属性的对象。

    服务器端:

    index2.php

    <?php
    
    $data = file_get_contents('php://input'); // 从 php://input 里获得原始输入流
    $data = json_decode($data, true);
    
    $response['code'] = 200;
    $response['message'] = 'success';
    $response['data'] = $data;
    
    header('content-type:text/json');
    exit(json_encode($response));

    POST 数据:

    响应:

    4. JSONP 

    同源策略:

    浏览器有一种同源策略(Same origin policy),同源是指域名、协议、端口相同,当浏览器执行一个脚本(例如 JavaScript)的时候会检查这个脚本是否同源,否则不会执行该脚本,因为浏览器认为来自同站点的资源是安全的。在浏览器中,<script>、<img>、<iframe>、<link> 等标签都可以加载跨域资源,而不受同源限制,但浏览器限制了JavaScript 的权限使其不能读、写加载的内容。另外同源策略只对网页的 HTML 文档做了限制,对加载的其他静态资源如 JavaScript、css、图片等仍然认为属于同源。(参考:

    同源策略同源策略和跨域访问)。

    例如,客户端通过 XMLHttpRequest 跨域与服务端交互,访问 http://www.site1.com/ajaxjson.html

    ajaxjson.html:

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
        <script src="http://lib.sinaapp.com/js/jquery/1.9.1/jquery-1.9.1.min.js"></script>
    </head>
    <body>
        <script>
        $.ajax({
            url: "http://www.site2.com/index.php",
            type: "post",
            success: function(data) {
                console.log(data);
            },
            error: function() {
                console.log("error");
            }
        });
        </script>
    </body>
    </html>

    由于请求的域是 www.site2.com,属于跨域请求,所以在访问 http://www.site1.com/ajaxjson.html 时,浏览器会给出提示:

    火狐下:

    Chrome 下:

    要解决这类跨域问题,可以使用 JSONP 作为解决方案。 

    JSONP:JSON with padding(参数式 JSON),包含在函数调用中的 JSON。如:

    callback({"name": "dee"});

    JSONP 利用在页面中创建 <script> 节点的方法向不同域提交 HTTP请求。例,两个域 http://www.site1.com 和 http://www.site2.com 实现跨域交互

    客户端 site/index.html:

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>site1</title>
    </head>
    <body>
        <p id="response"></p>
    </body>
    <script>
        function jsonCallback(data) {
            document.getElementById("response").innerText = data.name;
            console.log(data);
        }
    </script>
    <script src="http://www.site2.com/index.php?callback=jsonCallback "></script>
    </html>

    服务端 site2/index.php:

    <?php
    
    $callback = isset($_GET['callback']) ? $_GET['callback'] : '';
    
    echo $callback.'({"name": "emperor"})';

    访问 http://www.site1.com/index.html,返回:

    说明:

    其中 jsonCallback 是客户端注册的,获取跨域服务器上的 json 数据后,回调的函数。http://www.site2.com/index.php?callback=jsonpCallback 这个 url 是跨域服务器取 json 数据的接口,参数为回调函数的名字,返回的格式为:jsonpCallback({"name": "dee"})
    
    简述原理与过程:首先在客户端注册一个 callback, 然后把 callback 的名字传给服务器。此时,服务器先生成 json 数据。 然后以 javascript 语法的方式,生成一个function , function 名字就是传递上来的参数 jsonp 。最后将 json 数据直接以入参的方式,放置到 function 中,这样就生成了一段 js 语法的文档,返回给客户端。
    
    客户端浏览器,解析 script 标签,并执行返回的 javascript 文档,此时数据作为参数,传入到了客户端预先定义好的 callback 函数里。(动态执行回调函数)

    (参考 JSONP跨域的原理解析) 

    同样的,jQuery 也对 JSONP 进行了封装,可以使用 jQuery 进行跨域请求:

    site1/ajaxjsonp.html

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
        <script src="http://lib.sinaapp.com/js/jquery/1.9.1/jquery-1.9.1.min.js"></script>
    </head>
    <body>
        <script>
        $.ajax({
            url: "http://www.site2.com",
            dataType: "jsonp", // Tell jQuery we're expecting JSONP
            jsonp: "callback", // 回调参数的名称 The name of the callback parameter
            success: function(data) {
                console.log(data);
            },
            error: function() {
                console.log("error");
            }
        });
        </script>
    </body>
    </html>

    浏览器此时不会再提示已组织跨源请求而返回了服务端的数据:

    JSONP 的优点是:它不像 XMLHttpRequest 对象实现的 Ajax 请求那样受到同源策略的限制;它的兼容性更好,在更加古老的浏览器中都可以运行,不需要 XMLHttpRequest 或 ActiveX 的支持;并且在请求完毕后可以通过调用 callback 的方式回传结果。

    JSONP 的缺点则是:它只支持 GET 请求而不支持 POST 等其它类型的 HTTP 请求。(参考 JSONP跨域的原理解析

    JSONP的最基本的原理是:动态添加一个 <script> 标签,而 script 标签的 src 属性是没有跨域的限制的。这样说来,这种跨域方式其实与 ajax XmlHttpRequest 协议无关了。更多原理可以参考 JSONP跨域的原理解析

    如果设为dataType: 'jsonp',这个$.ajax方法就和ajax XmlHttpRequest没什么关系了,取而代之的则是JSONP协议。JSONP是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问。
    
    JSONP即JSON with Padding。由于同源策略的限制,XmlHttpRequest只允许请求当前源(域名、协议、端口)的资源。如果要进行跨域请求, 我们可以通过使用html的script标记来进行跨域请求,并在响应中返回要执行的script代码,其中可以直接使用JSON传递javascript对象。 这种跨域的通讯方式称为JSONP。
    
    jsonCallback 函数jsonp1236827957501(....):是浏览器客户端注册的,获取跨域服务器上的json数据后,回调的函数
    
    Jsonp的执行过程如下:
    
    首先在客户端注册一个callback (如:'jsoncallback'), 然后把callback的名字(如:jsonp1236827957501)传给服务器。注意:服务端得到callback的数值后,要用jsonp1236827957501(......)把将要输出的json内容包括起来,此时,服务器生成 json 数据才能被客户端正确接收。
    
    然后以 javascript 语法的方式,生成一个function, function 名字就是传递上来的参数 'jsoncallback'的值 jsonp1236827957501 .
    
    最后将 json 数据直接以入参的方式,放置到 function 中,这样就生成了一段 js 语法的文档,返回给客户端。
    
    客户端浏览器,解析script标签,并执行返回的 javascript 文档,此时javascript文档数据,作为参数, 传入到了客户端预先定义好的 callback 函数(如上例中jquery $.ajax()方法封装的的success: function (json))里。
    
    可以说jsonp的方式原理上和<script src="http://跨域/...xx.js"></script>是一致的(qq空间就是大量采用这种方式来实现跨域数据交换的)。JSONP是一种脚本注入(Script Injection)行为,所以有一定的安全隐患。

    5.其他跨域解决方案

    CORS(跨域资源共享,Cross-Origin Resource Sharing)是 W3 的一项机制(https://www.w3.org/TR/cors/),跨源资源共享标准通过新增一系列 HTTP 头,让服务器能声明哪些来源可以通过浏览器访问该服务器上的资源。

    例:

    在 site2/cors.php 中添加 header:

    header('Access-Control-Allow-Origin: *');

    * 表示允许任何域向服务端提交请求

    服务端代码:

    <?php
    
    header('Access-Control-Allow-Origin: *');
    
    $response['code'] = 200;
    $response['message'] = 'success';
    $response['name'] = 'dee';
    
    header('Content-type: text/json');
    exit(json_encode($response));

    客户端 site1/cors.html

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
        <script src="http://lib.sinaapp.com/js/jquery/1.9.1/jquery-1.9.1.min.js"></script>
    </head>
    <body>
        <script>
        $.ajax({
            url: "http://www.site2.com/cors.php",
            type: "post",
            dataType: "json",
            success: function(data) {
                console.log(data);
            },
            error: function() {
                console.log("error");
            }
        });
        </script>
    </body>
    </html>

    浏览器 console 输出:

    当把 header 改为:

    header('Access-Control-Allow-Origin: http://www.site3.com');

    即只允许来自 http://www.site3.com 的 AJAX 请求

    再次访问 http://www.site1.com,由于设置了只允许 site3 的 AJAX 请求,所以浏览器输出:

     

    把 header 再次改为:

    header('Access-Control-Allow-Origin: http://www.site1.com');

    输出:

    参考:

    json.org

    《JavaScript高级程序设计》3nd

    《精通jQuery》2nd

    https://learn.jquery.com/ajax/working-with-jsonp/

    JSONP跨域的原理解析

    HTTP访问控制(CORS)

    AJAX POST&跨域 解决方案 - CORS

     
  • 相关阅读:
    2019 年 GrapeCity Documents 产品路线图
    2019 年 Spread.NET 产品路线图(Roadmap)
    ActiveReports报表控件 V13 正式发布,提供在线报表设计和自适应报表布局
    ActiveReports 大数据分析报告:2018中国电影再次迎来黄金时代
    【Visual Studio 扩展工具】如何在ComponentOne的DataTree中实现RightToLeft布局
    JavaScript-页面打印正方形,各种三角形与菱形
    HTML入门与基础 —— 标签《一》
    springmvc异常处理
    springmvc-数据回显
    springmvc-validation校验
  • 原文地址:https://www.cnblogs.com/dee0912/p/5494649.html
Copyright © 2011-2022 走看看