JSON (JavaScript Object Notation) is a lightweight data-interchange format. 即 JSON 是一種輕量級的數據交換格式。javascript
JSON 構建於於兩種(除去簡單值)結構(JSON is built on two structures) php
① 對象:名稱(鍵) / 值對的集合(A collection of name / value pairs):css
{ "key1": "value1", "key2": "value2" }
或者html
{ "name": "dee", "age": 28, "stack": { "frontend": "JavaScript", "backend": "php" } }
說明:java
一個對象以 { 開始,} 結束。每一個名稱(name)後跟一個 :node
每一個鍵值對之間使用 , 分隔mysql
注意:JSON 對象屬性裏的非數字型鍵值必需要加雙引號,不能不加或者加單引號。jquery
② 數組:值(value)的有序集合(An array is an ordered collection of values)linux
相似於 JavaScript 中的數組:ajax
["dee", 28, "developer"]
把對象和數組結合起來,能夠構建更復雜的數據集合:
[ { "title": "PHP Cookbook", "authors": [ "Sklar", "Adam" ], "edition": 3 }, { "title": "Modern PHP", "authors": "Lockhart" } ]
說明:
一個數組以 [ 開始,] 結束。值之間使用 , 分隔。
值(value)能夠是字符串(string)、數值(number)、true
、false
、 null
、對象(object)或者數組(array)。這些結構能夠嵌套。字符串類型的值必須雙引號括起來。
解析:把 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):
① 獲取 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 數據:
響應:
同源策略:
瀏覽器有一種同源策略(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)行爲,因此有必定的安全隱患。
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');
輸出:
參考:
《JavaScript高級程序設計》3nd
《精通jQuery》2nd