關於ajax,json以及jsonp

Q:AJAX以何種格式來交換數據?跨域的需求如何解決?javascript

A:用JSON來傳數據,靠JSONP來跨域(具體參見下文)php

AJAX

建立對象

AJAX = Asynchronous(英[eɪˈsɪŋkrənəs]) JavaScript and XML(異步的 JavaScript 和 XML)。java

XMLHttpRequest 用於在後臺與服務器交換數據。這意味着能夠在不從新加載整個網頁的狀況下,對網頁的某部分進行更新。node

建立兼容對象

全部現代瀏覽器均支持 XMLHttpRequest 對象(IE5 和 IE6 使用 ActiveXObject)。jquery

// 建立 XMLHttpRequest 對象
var xmlhttp;
if (window.XMLHttpRequest)
  {// code for IE7+, Firefox, Chrome, Opera, Safari
  xmlhttp=new XMLHttpRequest();
  }
else
  {// code for IE6, IE5
  xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
  }
// 向服務器發送請求
// 當使用 async=true 時,請規定在響應處於 onreadystatechange 事件中的就緒狀態時執行的函數
// async=false 時,請不要編寫 onreadystatechange 函數 - 把代碼放到 send() 語句後面便可
xmlhttp.onreadystatechange=function(){
  if (xmlhttp.readyState==4 && xmlhttp.status==200){
    // 來自服務器的響應 responseText:字符串形式 responseXML:XML形式
    document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
  }
}
xmlhttp.open("GET","test1.txt",true);
xmlhttp.send();

發送請求

XMLHttpRequest 方法

  • open(method,url,async)web

    method:請求的類型;GET 或 POST
    url:文件在服務器上的地址(該文件能夠是任何類型的文件或服務器腳本文件)
    async:true(異步)或 false(同步)
  • send(string)ajax

    string:僅用於 POST 請求

GET 仍是 POST?

與 POST 相比,GET 更簡單也更快,而且在大部分狀況下都能用。
然而,在如下狀況中,請使用 POST 請求:
沒法使用緩存文件(更新服務器上的文件或數據庫)
向服務器發送大量數據(POST 沒有數據量限制)
發送包含未知字符的用戶輸入時,POST 比 GET 更穩定也更可靠數據庫

避省得到的是緩存的結果,向URL添加一個惟一的 IDjson

xmlhttp.open("GET","demo_get.asp?t=" + Math.random(),true);

但願經過 GET 方法發送信息,請向 URL 添加信息跨域

xmlhttp.open("GET","demo_get2.asp?fname=Bill&lname=Gates",true);

須要像 HTML 表單那樣 POST 數據,請使用 setRequestHeader() 來添加 HTTP 頭。而後在 send() 方法中規定您但願發送的數據

// 向請求添加 HTTP 頭。
// setRequestHeader(header,value)
// header: 規定頭的名稱 value: 規定頭的值
xmlhttp.open("POST","ajax_test.asp",true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send("fname=Bill&lname=Gates");

服務器響應

XMLHttpRequest 對象的 responseText 或 responseXML 屬性

responseText:字符串形式

document.getElementById("myDiv").innerHTML=xmlhttp.responseText;

responseXML:XML形式

// 請求 books.xml 文件,並解析響應   
xmlDoc=xmlhttp.responseXML;
txt="";
x=xmlDoc.getElementsByTagName("ARTIST");
for (i=0;i<x.length;i++)
  {
  txt=txt + x[i].childNodes[0].nodeValue + "<br />";
  }
document.getElementById("myDiv").innerHTML=txt;

readyState

當請求被髮送到服務器時,咱們須要執行一些基於響應的任務。
readyState 屬性存有 XMLHttpRequest 的狀態信息。
每當 readyState 改變時,就會觸發 onreadystatechange 事件。

XMLHttpRequest 對象的三個重要的屬性

  • onreadystatechange

    存儲函數(或函數名),每當 readyState 屬性改變時,就會調用該函數。
  • readyState

    存有 XMLHttpRequest 的狀態。從0到4發生變化。(一共被觸發 5 次)
    0: 請求未初始化
    1: 服務器鏈接已創建
    2: 請求已接收
    3: 請求處理中
    4: 請求已完成,且響應已就緒
  • status

    200: "OK"
    404: 未找到頁面

使用 Callback 函數

callback 函數是一種以參數形式傳遞給另外一個函數的函數

JSON

JavaScript 對象表示法(JavaScript Object Notation)
是存儲和交換文本信息的語法。相似 XML,比XML更小、更快,更易解析。
JSON有六種類型的值:對象,數組,字符串,數字,布爾值和特殊值null。

JSON 語法規則

數據在名稱/值對中
數據由逗號分隔
花括號保存對象
方括號保存數組

JSON具備兩種結構:對象,數組

對象結構以」{」大括號開始,以」}」大括號結束。中間部分由0或多個以」,」分隔的」key(關鍵字)/value(值)」對構成,關鍵字字符串和值之間以」:」分隔

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

數組結構以」[」開始,」]」結束。中間由0或多個以」,」分隔的值列表組成

[
   {
       key1:value1,
       key2:value2,
      ...
   },
   {
       key1:value1,
       key2:value2,
      ...
   },
]

JSON的解析與序列化

JSON對象(ECMAScript 5中添加的, 早期JSON解析基本都使用javascript的eval()函數。可是eval有一些性能和安全上的缺點,ECMAScript對解析JSON對象進 行了規範,定義了全局對象JSON,支持的瀏覽器有標準瀏覽器和IE8+。對於不支持的瀏覽器能夠引入json2.js文件。)有stringify與parse這兩個方法。

JSON.stringify

將javascript對象序列化爲JSON格式的字符串

JSON.stringify(ob,filter,indent)包含三個參數,一般咱們在使用的時候只帶第一個參數,來返回字符串。

  • ob:要轉化成JSON字符串的對象,數組,原始值。

  • filter:是一個可選的參數,一般是一個函數,用來在字符串化前對值作一些替換。也能夠是一個數組,包含哪些須要字符串化的屬性名。就是用來過濾的。

// 第二個參數是數組過濾器
var oJson = { name: 'hum', age: 20, sex: 1};
console.log(JSON.stringify(oJson, ['age', 'sex'])); 
// {"age":20,"sex":1}

// 第二個參數是函數過濾器
// 若是該參數是函數,則它是一個替換函數,該函數會在每個須要字符串化的對象上調用。
// 這個函數的第一個參數是該對象中的屬性名或數組的序號,第二個則是值自己。
// 函數的返回值會替換掉須要字符串化的值,若是函數返回undefined或沒有任何的返回值,則會在字符串化的時候忽略這個值。
var oJson = { name: 'hum', age: 26, sex: 1, love: ['swing', 'jump']};
console.log(JSON.stringify(oJson, function(k, v){
    switch (k){
        case 'age':
            return v > 20 ? '成年': '未成年';
        case 'love':
            return v.join(',');
        case 'sex':
            return undefined;
        default :
            return v;
    }
})); 
// {"name":"hum","age":"成年","love":"swing,jump"}
  • indent:也是一個可選參數,在須要輸出格式化的可閱讀的代碼時,使用indent參數來指定用來縮進的字符串或空格。若是省略該參數,返回的字符串將不帶任何的額外的空格,這樣輸出的值很難閱讀。就是用來格式化的。

JSON.parse

JSON.parse用來解析json格式的字符串(返回一個對象,數組或原始值)
JSON.parse(s,reviver)包含兩個參數

  • s:要解析的字符串

  • reviver:用來轉換解析值得可選函數

一般使用只使用第一個參數,可選參數reviver,主要是在返回解析值以前,對其進行過濾或後期處理。
reviver函數會在從s中解析的每一個原始值調用一次。
調用reviver函數是帶有兩個參數,第一個屬性名(對象的屬性名或是轉換成字符串的數組序號),第二個參數是對象的屬性或是數組的元素值。
reviver函數會做爲包含原始值的對象/數組的方法來調用。
reviver函數的返回值會成爲屬性的新值,若是reviver返回第二個參數,則屬性不變。
若是reviver返回undefined或不凡會任何值,則會從對象或是數組中刪除屬性。

var oJson = { name: 'hum', age: 26, sex: 1, love: ['swing', 'jump'], birthday: '1988-01-12'};
var sJson = JSON.stringify(oJson);
console.log(sJson);
//{"name":"hum","age":26,"sex":1,"love":["swing","jump"],"birthday":"1988-01-12"}
console.log(JSON.parse(sJson));
console.log(JSON.parse(sJson, function (k, v) {
    if(k == 'birthday'){ // 返回日期對象
        return new Date(v);
    }else if(k == 'sex'){ // sex不在了
        return undefined;
    }else{
        return v;
    }
}));

JSON格式化工具

http://www.runoob.com/jsontool

JSONP

Jsonp(JSON with Padding) 是 json 的一種"使用模式",可讓網頁從別的域名(網站)那獲取資料,即跨域讀取數據。

JSONP是怎麼產生的?

一、衆所周知,Ajax直接請求普通文件存在跨域無權限訪問的問題(緣由參見 同源策略-web腳本安全)

二、可是,HTML的<script>標籤是例外,能夠突破同源策略從其餘來源獲取數據(實質是擁有"src"這個屬性的標籤都擁有跨域的能力,好比<script>、<img>、<iframe>)

三、因而能夠判斷,當前階段若是想經過純web端(ActiveX控件、服務端代理、屬於將來的HTML5之Websocket等方式不算)跨域訪問數據就只有一種可能,那就是在遠程服務器上設法把數據裝進js格式的文件裏,供客戶端調用和進一步處理(如今可使用nodejs作中間件了,本文暫且不表,改天我詳細寫一下~);

JSONP原理

首先在客戶端註冊一個callback, 而後把callback的名字傳給服務器。

此時,服務器先生成 json 數據。

而後以 javascript 語法的方式,生成一個function , function 名字就是傳遞上來的參數 jsonp.

最後將 json 數據直接以入參的方式,放置到 function 中,這樣就生成了一段 js 語法的文檔,返回給客戶端。

客戶端瀏覽器,解析script標籤,並執行返回的 javascript 文檔,此時數據做爲參數,傳入到了客戶端預先定義好的 callback 函數裏.(動態執行回調函數)

應用代碼

// 原生js 添加<script>標籤的方法 
//(函數名可約定,或經過地址參數傳遞)
function addScriptTag(src){
    var script = document.createElement('script');
    script.setAttribute("type","text/javascript");
    script.src = src;
    document.body.appendChild(script);
}

 window.onload = function(){
     //將自定義的回調函數名result傳入callback參數中
     addScriptTag("localhost/bns-relation/index.php?r=BnsRelation/BnsOfProd&callback=result");

}
 //自定義的回調函數result
 function result(data) {
     //咱們就簡單的獲取數據
    console.log(data);
 }
// zepto,jquery的JSONP用法
var qsData = {'searchWord':$("#searchWord").attr("value"),'currentUserId':
$("#currentUserId").attr("value"),'conditionBean.pageSize':$("#pageSize").attr("value")};

$.ajax({ 
    async:false, 
       url: http://跨域的dns/document!searchJSONResult.action, 
       type: "GET", 
       dataType: 'jsonp', 
       jsonp: 'jsoncallback', 
       data: qsData, 
       timeout: 5000, 
       beforeSend: function(){ 
           //jsonp 方式此方法不被觸發.緣由多是dataType若是指定爲jsonp的話,就已經不是ajax事件了 
       }, 
       success: function (json) {//客戶端jquery預先定義好的callback函數,成功獲取跨域服務器上的json數據後,會動態執行這個callback函數 
        if(json.actionErrors.length!=0){ 
              alert(json.actionErrors); 
         } 
           genDynamicContent(qsData,type,json); 
       }, 
       complete: function(XMLHttpRequest, textStatus){ 
        $.unblockUI({ fadeOut: 10 }); 
       }, 
       error: function(xhr){ 
        //jsonp 方式此方法不被觸發.緣由多是dataType若是指定爲jsonp的話,就已經不是ajax事件了 
        //請求出錯處理 
        alert("請求出錯(請檢查相關度網絡情況.)"); 
       } 
});

JSONP優缺點

JSONP的優勢

不像XMLHttpRequest對象實現的Ajax請求那樣受到同源策略的限制;
兼容性更好,在更加古老的瀏覽器中均可以運行,不須要XMLHttpRequest或ActiveX的支持;
在請求完畢後能夠經過調用callback的方式回傳結果。

JSONP的缺點

只支持GET請求而不支持POST等其它類型的HTTP請求;
只支持跨域HTTP請求這種狀況,不能解決不一樣域的兩個頁面之間如何進行JavaScript調用的問題。

summary

ajax和jsonp其實本質上是不一樣的東西
ajax的核心是經過XmlHttpRequest獲取非本頁內容
而jsonp的核心則是動態添加<script>標籤來調用服務器提供的js腳本

JSON(JavaScript Object Notation)和JSONP(JSON with Padding)雖然只一個字母差異,但其實根本不是一回事兒JSON是一種數據交換格式而JSONP是一種非官方跨域數據交互協議

相關文章
相關標籤/搜索