讀javascript高級程序設計15-Ajax,CORS,JSONP,Img Ping


平時用慣了jQuery.ajax之類的方法,卻時常忽略了它背后的實現,本文是學習了AJAX基礎及幾種跨域解決方案之后的一些收獲。

一、AJAX——XMLHttpRequest

談起Ajax我們都很熟悉,它的核心對象是XMLHttpRequest(簡稱XHR)。

1.創建對象:

在ie7及以上版本支持原生的寫法創建該對象。

var xhr=new XMLHttpRequest();

2.發送請求:

open(type,url,isasync):第一個參數是請求類型(get,post),第二個參數是要請求的url,第三個參數是bool值表示是否為異步請求。該方法沒有真正的發送請求,只是啟動了一個請求以備發送。

send(body):該方法用來真正的發送請求,參數是請求真正要發送的數據內容。參數是必填項,即便不需要向服務器發送內容,也要傳遞參數null。

【備注】在get請求中,如果url結尾有查詢字符串,那么必須先對其鍵和值都要進行encodeURIComponent()編碼。

3.響應結果:請求的響應結果會自動復制到xhr對象的屬性中。

  • status:響應結果的狀態碼。
  • statusText:響應結果狀態說明。
  • responseText:響應返回的文本結果主體;
  • responseXML:如果響應的內容類型為"text/xml",那么結果會以XML DOM的格式賦值在該屬性中。如果請求結果是非XML格式,該屬性為null。

4.異步請求

大多數情況下我們都需要使用異步請求,此時可以通過檢測請求的readyState來判斷請求是否已經完成。實際上,每次readyState屬性改變時都會觸發一次onstatechange事件。readyState屬性有五種取值情況:

  • 0:未初始化,也就是還未調用open()方法;
  • 1:啟動,已經調用open()方法,尚未調用send()方法;
  • 2:發送,已經調用send()方法,還未收到響應;
  • 3:接收。已經接收到一部分響應結果數據;
  • 4:完成。已經接收到全部響應數據,可以在客戶端調用了(最常用)。

【備注】為了保證瀏覽器兼容性,需要在調用open()方法之前指定onreadystatechange事件處理程序。

5.自定義HTTP請求頭

setRequestHeader(key,value):發送自定義消息頭。最常用的場景是在post請求中模擬表單提交:xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

【備注】該方法必須在open()之后send()之前調用。

6.簡例 demo1.html:

var obj= document.getElementById("result");   
           //創建XHR對象   
        var xhr = new XMLHttpRequest();
        //狀態變化事件
        xhr.onreadystatechange=function(){
             obj.innerHTML+="readyState:"+xhr.readyState+"<br/>";
             //請求完成
             if(xhr.readyState==4){
                       //響應結果    
                       if ((xhr.status==200) || xhr.status == 304){
                            var msg="status:"+xhr.status+"<br/>";
                            msg+="statusText:"+xhr.statusText+"<br/>";
                            msg+="responseText:"+xhr.responseText;
                            obj.innerHTML+=msg;
                       } else {
                           alert("請求失敗: " + xhr.status);
                       } 
                  }
             }  
        //啟動請求   
        xhr.open("get", "weather.json", true);
        //自定義HTTP頭
        xhr.setRequestHeader("testheader","hello");
        //發送請求
        xhr.send(null);

Image

Image(1)

二、XHR進度事件

1.load事件

load事件是在響應結果接收完畢時調用,可以用來簡化readystatechange事件。不過,只要瀏覽器接收到結果就會觸發該事件,因此還需要自行判斷響應狀態status。

xhr.onload=function(){
                       if ((xhr.status==200) || xhr.status == 304){                          
                            obj.innerHTML+="responseText:"+xhr.responseText;

                       } else {
                           alert("請求失敗: " + xhr.status);
                       } 
             }

2.progress事件

progress事件會在瀏覽器接收數據的過程中周期性觸發。onprogress事件處理程序可以接收到event對象參數,其中event.targe是xhr對象,它還有三個重要的屬性:

  • lengthComputable:布爾值,表示進度是否可用;
  • loaded:已經接收的字節數;
  • total:根據響應頭中的Content-Length預期需要接收的總字節數。
xhr.onprogress=function(event){
             if(event.lengthComputable){
                  objstatus.innerHTML=event.loaded+"/"+event.total;
                  }
             }

三、跨域資源共享(CORS)

XHR的一個主要約束是同源策略,即:相同域、相同端口、相同協議,可以通過跨域資源共享CORS(Cross-Origin Resourse Sharing)實現跨域資源共享。其基本思想是通過自定義HTTP頭讓瀏覽器與服務器溝通,從而確定是否正常響應。如果服務器允許請求,則在響應頭添加"Access-Control-Allow-Origin" 來回發源信息.

1.IE對CORS支持——XDR(XDomainRequest)

IE中使用XDR對象實現CORS,它的使用與XHR對象類似,也是實例化后調用open()和send()方法。不同的是,XDR的open()方法只有兩個參數:請求類型和URL。

xhr=new XDomainRequest();
xhr.open(method,url);
xhr.send();

2.其他瀏覽器支持CORS——原生XHR

大多數瀏覽器的XHR對象原生支持CORS,只需要在open()方法中傳入響應的url即可。

3.跨瀏覽器支持CORS

綜合以上兩種情況,可以實現跨瀏覽器的CORS。檢查XHR是否支持CORS的最簡單方式是檢查 withCredentials屬性,然后結合檢查XDomainRequest對象是否存在即可。

function createCORSRequest(method,url){
              //創建XHR對象   
        var xhr = new XMLHttpRequest();
        //啟動請求   
        if("withCredentials" in xhr){
             xhr.open(method,url,true);
             }else if(typeof XDomainRequest!='undefined'){
                  xhr=new XDomainRequest();
                  xhr.open(method,url);
                  }else{
                       xhr=null;
                       }                 
        return xhr;
              }

4.實例

下面看個簡單的例子,http://www.jsdemo.com/demoajax/demo3.htm 跨域請求 http://www.othersite.com/weather.ashx 中的數據。這是本地搭建的兩個測試站點,demo源碼見文章底部。

weather.ashx首先檢測來源頁面,然后決定是否返回Access-Control-Allow-Origin頭。

public void ProcessRequest (HttpContext context) {
        context.Response.ContentType = "text/plain";
        string referrer = context.Request.ServerVariables["HTTP_REFERER"];
        if (!string .IsNullOrEmpty(referrer) && referrer.IndexOf( "http://www.jsdemo.com") > -1)
        {
            context.Response.AddHeader( "Access-Control-Allow-Origin" , "http://www.jsdemo.com");
        }
        context.Response.Write( "{\"weather\": \"晴\",\"wind\": \"微風\"}" );
    }

demo3.htm通過CORS方式進行跨域請求,並將結果解析后顯示在頁面中。

var xhr=createCORSRequest("get","http://www.othersite.com/weather.ashx");
         xhr.onload=function(){
              if(xhr.status==200||xhr.status==304){
                   var result=xhr.responseText;
                   var json=JSON.parse(result);
                   var obj= document.getElementById("result");
                   obj.innerHTML="天氣:"+json.weather+";風力:"+json.wind;
                   }
              }
      xhr.send();

3

四、圖像跨域請求

<img>標簽是沒有跨域限制的,我們可以利用圖像標簽實現一種簡單的、單向的跨域通信。圖像ping通常用於跟蹤用戶點擊數和廣告曝光次數等。

特點:圖像跨域請求只能用於瀏覽器和服務器之間的單向通信,它只能發送Get請求,而且服務訪問服務器的響應內容。

來看個小例子demo4.htm,客戶端點擊鏈接時觸發跨域請求。

<a href="javascript:void(0);" onclick="Click()">點擊我</a>
    <script>
         function Click(){
              var img=new Image();
              img.onload=function(){
                   alert('DONE');
                   }
                   img.src="http://www.othersite.com/demo4.ashx?r="+Math.random();
              }
    </script>

服務端進行簡單的計數,並且發送回一像素大小的圖像。客戶端接收到該結果后會彈窗提示“DONE”。

public static int Count=0;

public void ProcessRequest (HttpContext context) {
        context.Response.ContentType = "text/plain" ;
        Count++;
        context.Response.ContentType = "image/gif" ;
        System.Drawing. Bitmap image = new System.Drawing. Bitmap(1, 1);
        image.Save(context.Response.OutputStream, System.Drawing.Imaging. ImageFormat .Gif);
        context.Response.Write(Count);
    }

五、JSONP跨域請求

1.JSONP結構

JSONP是很常用的一種跨域請求方案,常見的JSONP請求格式如下:

http://www.othersite.com/demo5.ashx?callback=showResult

響應結果看上去就像是包在函數調用中的JSON結構:

showResult({"weather": "晴","wind": "微風"})

JSONP結果由兩部分組成:回調函數和數據。回調函數一般是在發起請求時指定的,當響應完成時會在頁面中調用的函數;數據當然就是請求返回的JSON數據結果。

2.發起請求:

JSONP原理上是利用了動態<script>標簽實現的,通過創建script對象,並且將其src屬性設置為跨域請求的url地址。當請求完成后,JSONP響應加載到頁面中便立即執行。

<script>
         function showResult(json){                
                   var obj= document.getElementById("result");
                   obj.innerHTML="天氣:"+json.weather+";風力:"+json.wind;
      }
         var script=document.createElement("script");
         script.src="http://www.othersite.com/demo5.ashx?callback=showResult";
         document.body.insertBefore(script,document.body.firstChild);
    </script>

3.特點:

  • JSONP可以實現瀏覽器和服務器雙向通信,並且能夠訪問響應中的文本;
  • JSONP是從其他域中加載代碼並執行的,需要注意其安全性;
  • JSONP請求結果成敗不易確定。

 附件:DEMO源碼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM