JS學(xué)習(xí)19(Ajax與Comet)

Ajax:Asynchronous JavaScript + XML的簡寫。
Ajax技術(shù)的核心是XMLHttpRequest對象(XHR),XHR為向服務(wù)器發(fā)送請求和解析服務(wù)器響應(yīng)提供了流暢的接口。能夠以異步方式從服務(wù)器取得信息,再通過DOM將新數(shù)據(jù)插入到頁面中。

XMLHttpRequest對象

IE7+ Firefox Opera Chrome Safari原生支持XHR對象。

var xhr = new XMLHttpRequest();

XHR的用法

在使用XHR對象時,要調(diào)用的第一個方法是open(),它接受3個參數(shù):要發(fā)送的請求類型(get,post)、請求的URL、表示是否異步發(fā)送請求的布爾值。
這時就啟動了一個請求以備發(fā)送。

xhr.open("get", "example.php", false);

只能向同一個域中使用相同端口和協(xié)議的URL發(fā)送請求,如果URL與啟動請求的頁面有任何差別,都會引發(fā)安全錯誤。
要發(fā)送請求就要調(diào)用send()方法:

xhr.send(null);

send方法接收的參數(shù)是要作為請求主體發(fā)送的數(shù)據(jù),如果不需要數(shù)據(jù)就傳null,因為有的瀏覽器必須要傳這個數(shù)據(jù)。
如果請求是同步的,那么JS會在等到服務(wù)器響應(yīng)之后再繼續(xù)執(zhí)行。
等到響應(yīng)后,響應(yīng)的數(shù)據(jù)會自動填充XHR對象的屬性:

  • responseText:響應(yīng)主體的文本
  • responseXML:這個屬性中保存著包含響應(yīng)數(shù)據(jù)的XML DOM文檔
  • status:響應(yīng)的HTTP狀態(tài)
  • statusText:HTTP狀態(tài)的說明
var xhr = new XMLHttpRequest();
xhr.open("get", "16_.html", false);
xhr.send(null);
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
    alert(xhr.responseText);
} else {
    alert("Request was unsuccessful: " + xhr.status);
}

在發(fā)送異步請求時JS不會等待響應(yīng),此時的XHR會有readyState屬性,表示請求響應(yīng)過程的當(dāng)前活動階段:

  • 0:未初始化,尚未調(diào)用open方法
  • 1:啟動,已經(jīng)調(diào)用open未調(diào)用send
  • 2:發(fā)送,已經(jīng)調(diào)用send,未收到響應(yīng)
  • 3:接收,已經(jīng)接收到部分響應(yīng)數(shù)據(jù)
  • 4:完成,已經(jīng)接收到全部響應(yīng)數(shù)據(jù),且數(shù)據(jù)可用

readyState屬性發(fā)生改變時會觸發(fā)一次readystatechange事件,為確保瀏覽器兼容,需要在調(diào)用open前指定readystatechange事件處理程序。

var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
    alert(xhr.readyState);
    if (xhr.readyState == 4){
        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
            alert(xhr.responseText);
        } else {
            alert("Request was unsuccessful: " + xhr.status);
        }
    }
};
xhr.open("get", "16_.html", true);
xhr.send(null);

在接收到響應(yīng)之前可以通過abort方法取消異步請求

xhr.abort();

在終止請求,應(yīng)該解引用XHR對象,由于內(nèi)存原因不建議重用XHR對象。

HTTP頭部信息

每個HTTP請求和響應(yīng)都會帶有相應(yīng)的頭部信息,XHR對象也提供了操作這兩種頭部信息的方法。
默認(rèn)情況下,在發(fā)送XHR請求的同時還會發(fā)送下列頭部:

  • Accept
  • Accept-Charset
  • Accept-Encoding
  • Accept-Language
  • Connection
  • Cookie
  • Host
  • Referer
  • User-Agent

使用setRequestHeader()方法可以設(shè)置自定義的請求頭部。參數(shù)為頭部字段的名稱和頭部字段的值。這個要在open和send之間調(diào)用才有效。

xhr.setRequestHeader("MyHeader", "MyValue");

在使用這個方法時,建議使用自定義的頭部名,以免與瀏覽器發(fā)生沖突,有的瀏覽器可能不允許開發(fā)人員重寫默認(rèn)頭部。
想要獲得頭部的值可以使用下面這兩種方法。

var myHeader = xhr.getResponseHeader("MyHeader");
var allHeaders = xhr.getAllResponseHeaders();

GET請求

用于向服務(wù)器查詢某些信息,將參數(shù)放到后面。使用addURLParam就是保證URI被正確編碼,格式良好。

var xhr = new XMLHttpRequest();
function addURLParam(url, name, value) {
    url += (url.indexOf("?") == -1 ? "?" : "&");
    url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
    return url;
}
var url = "example.php";
url = addURLParam(url, "name", "Nicholas");
url = addURLParam(url, "book", "Professional JavaScript");

xhr.open("get", url, true);
xhr.send(null);

POST請求

用于向服務(wù)器發(fā)送應(yīng)該保存的數(shù)據(jù),POST請求應(yīng)該會發(fā)送很多的數(shù)據(jù)到服務(wù)器。這時send的參數(shù)就是發(fā)送的數(shù)據(jù)了。一般是數(shù)據(jù)序列化后的字符串。

var xhr = new XMLHttpRequest();
xhr.open("post", "postexample.php", true);
//模仿表單提交
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
var form = document.getElementById("user-info");
xhr.send(serialize(form));

GET請求消耗的資源少,同等數(shù)據(jù)量是POST的兩倍。

XMLHttpRequest 2級

FormData

Web應(yīng)用中頻繁使用的一項功能就是表單數(shù)據(jù)的序列化。為此,2級定義了FormData對象。
append方法可以向其添加數(shù)據(jù),鍵值對形式

var data = new FormData();
data.append("name", "Nicholas");

也可以直接使用表單初始化FormData:

var data = new FormData(document.forms[0]);
xhr.send(data);

創(chuàng)建好的FormData的實例后直接傳給XHR的send方法,這時XHR會自動幫你照顧好頭部信息。

超時設(shè)定

2級中又規(guī)定了一個timeout屬性,表示請求在等待響應(yīng)多少毫秒之后就終止。設(shè)置之后,如果超時沒有接收到響應(yīng),就回觸發(fā)timeout事件,調(diào)用事件處理程序,這時xhr.readyState可能已經(jīng)為4了,但是此時請求已經(jīng)中止了,不能再訪問xhr.status,所以如果使用timeout,onreadystatechange事件處理也要小心。

var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
    if (xhr.readyState == 4){
        try {
            if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
                alert(xhr.responseText);
            } else {
                alert("Request was unsuccessful: " + xhr.status);
            }
        } catch (ex){

        }
    }
};
xhr.open("get", "timeout.php", true);
xhr.timeout = 1000; //      IE8+
xhr.ontimeout = function(){
    alert("Request did not return in a second.");
};
xhr.send(null);

overrideMimeType()方法

重寫XHR響應(yīng)的MIME類型,因為響應(yīng)的MIME類型決定了XHR對象如何處理它。如果服務(wù)器返回的是XML文件,MIME卻是text/plain,那XHR對象就不能正確的設(shè)置responseXML。
要在send之前調(diào)用這個方法。

var xhr = createXHR(); xhr.open("get", "text.php", true); xhr.overrideMimeType("text/xml"); xhr.send(null);

進(jìn)度事件

Progress Events定義了與客戶端服務(wù)器通信有關(guān)的事件,這些事件最早其實只針對XHR,但目前也被其它API借鑒,有6個進(jìn)度事件:

  • loadstars:在接收到響應(yīng)數(shù)據(jù)的第一個字節(jié)時觸發(fā)
  • progress:在接收響應(yīng)期間不斷觸發(fā)
  • error:在請求發(fā)生錯誤時觸發(fā)
  • abort:在因為調(diào)用abort()方法而終止連接時觸發(fā)
  • load:在接收到完整響應(yīng)數(shù)據(jù)時觸發(fā)
  • loaded:在通信完成(觸發(fā)error、abort、load事件后)時觸發(fā)

支持前5個事件的有Firefox 3.5+、Safari 4+、Chrome、iOS 版Safari、Android 版 WebKit。
Opera 11+、IE8+只支持load事件。

load事件

只要瀏覽器接收到服務(wù)器的響應(yīng),不管其狀態(tài)如何都會觸發(fā)load事件,這就意味著必須檢查XHR對象的status屬性。對于這個事件有的瀏覽器實現(xiàn)了event對象,其target指向XHR對象,直接就可以使用所有對象和方法,可是有的瀏覽器并沒有實現(xiàn)。這就是說還得使用原來的全局XHR變量對象。

var xhr = new XMLHttpRequest();
xhr.onload = function(){
    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
        alert(xhr.responseText);
    } else {
        alert("Request was unsuccessful: " + xhr.status);
    }
};
xhr.open("get", "altevents.php", true);
xhr.send(null);

progress事件

這個事件會在瀏覽器接收數(shù)據(jù)的過程中持續(xù)的觸發(fā),其target屬性為XHR對象再加額外3個屬性:

  • lengthComputable:表示進(jìn)度信息是否可用
  • position:表示已經(jīng)接收到的字節(jié)數(shù)
  • totalSize:根據(jù)Content-Length響應(yīng)頭部確定的預(yù)期字節(jié)數(shù)

這個可以用來作為進(jìn)度指示器

var xhr = new XMLHttpRequest();
xhr.onprogress = function(event){
    var divStatus = document.getElementById("highDiv");
    if (event.lengthComputable) {
        divStatus.innerHTML = "Received " + event.position + " of " +
            event.totalSize + " bytes";
    }
};
xhr.open("get", "img/paypal2.png", true);
xhr.send(null);

跨源資源共享

通過XHR實現(xiàn)Ajax通信的一個主要限制,來源于跨域安全策略。默認(rèn)情況下,XHR對象只能訪問與包含它的頁面位于同一個域中的資源。這種安全策略可以預(yù)防某些惡意行為,但實現(xiàn)合理的跨域請求也是一個很重要的需求。
CORS(Cross-Orign Resource Sharing)就是為了這樣的需求而生的。
其背后的思想就是使用自定義的HTTP頭部讓瀏覽器與服務(wù)器進(jìn)行溝通,從而決定請求或響應(yīng)應(yīng)該成功還是失敗。
比如一個簡單的使用GET或POST發(fā)送的請求,添加一個自定義頭部Origin來包含請求頁面的源信息(協(xié)議,域名和端口),以便服務(wù)器根據(jù)這個頭部信息來決定是否響應(yīng)。如果服務(wù)器認(rèn)為這個請求可以接受,那么就在Access-Control-Allow-Origin頭部中發(fā)回相同的源或*,瀏覽器會檢查這個頭部,如果不符合則駁回請求。
這里的跨域請求和響應(yīng)都不會包含cookie。

IE對CORS的實現(xiàn)

IE8中引入了XDR(XDomainRequest)類型,它與XHR相似,是用來實現(xiàn)安全可靠的跨域通信的。在安全機制方面,XDR實現(xiàn)了部分CORS規(guī)范:

  • cookie不會隨請求發(fā)送,也不會隨響應(yīng)返回
  • 只能設(shè)置請求頭部中的Content-Type字段
  • 不能訪問響應(yīng)頭部
  • 只支持GET和POST

這些變化使得CSRF跨站點請求偽造和跨站點腳本的問題得到緩解,被請求的資源可以根據(jù)它認(rèn)為合適的請求來決定是否設(shè)置Access-Control- Allow-Origin。作為請求的一部分Origin會自動設(shè)置為當(dāng)前域。XDR只能發(fā)送異步請求。請求返回后會觸發(fā)load事件。

var xdr = new XDomainRequest();
xdr.onload = function(){
    alert(xdr.responseText);
};
xdr.onerror = function(){
    alert("An error occurred.");
};
xdr.open("post", "http://www.somewhere-else.com/page/");
xdr.contentType = "application/x-www-form-urlencoded";
xdr.send("name1=value1&name2=value2");

因為無法讀取響應(yīng)頭部,也就無法獲取狀態(tài)碼。只要響應(yīng)有效就回觸發(fā)load事件,失敗就觸發(fā)error事件。
abort方法可以終止請求
XDR也有timeout屬性和ontimeout事件處理程序。

其它瀏覽器對CORS的實現(xiàn)

其它大多數(shù)瀏覽器并沒有使用新類型的對象來實現(xiàn)CORS,而是直接使用XHR原生支持。
如果要訪問其他域下的資源在XHR的open方法中傳入絕對URL即可。
這里不僅可以訪問到status和statusText屬性,還可以發(fā)起同步請求。
不過限制還是有的:

  • 不能發(fā)送接受cookie
  • 不能使用setRequestHeader()設(shè)置自定義頭部
  • 調(diào)用getAllResponseHeaders()總會返回空字符串
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
    if (xhr.readyState == 4){
        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
            alert(xhr.responseText);
        } else {
            alert("Request was unsuccessful: " + xhr.status);
        }
    } };
xhr.open("get", "http://www.somewhere-else.com/page/", true);
xhr.send(null);

Preflighted Reqeusts

CORS使用Preflighted Reqeusts的透明服務(wù)器驗證機制支持開發(fā)人員使用自定義頭部和GET或POST之外的方法以及不同類型的主體內(nèi)容。
在使用下列高級選項來發(fā)送請求時,就會向服務(wù)器發(fā)送一個Preflight請求。這種請求使用OPTIONS方法

  • Origin:與簡單請求相同
  • Access-Control-Request-Method:請求自身使用的方法
  • Access-Control-Request-Headers:自定義的頭部
Origin: http://www.nczonline.net
Access-Control-Request-Method: POST
Access-Control-Request-Headers: NCZ

發(fā)送這個請求后,服務(wù)器可以決定是否允許這種類型的請求并發(fā)送響應(yīng)頭部與瀏覽器溝通:

  • Access-Control-Allow-Origin
  • Access-Control-Allow-Methods
  • Access-Control-Allow-Headers
  • Access-Control-Max-Age:這個Preflighted請求應(yīng)該被緩存多久
Access-Control-Allow-Origin: http://www.nczonline.net
Access-Control-Allow-Methods: POST, GET
Access-Control-Allow-Headers: NCZ
Access-Control-Max-Age: 1728000

IE10及之前的版本不支持

帶憑據(jù)的請求

默認(rèn)情況下,跨源請求不帶憑據(jù)(cookie,HTTP認(rèn)證,SSL證明等)通過將withCredentials屬性設(shè)置為true,可以指定某個請求應(yīng)該發(fā)送憑據(jù)。如果服務(wù)器接受帶憑據(jù)的請求,會響應(yīng):Access-Control-Allow-Credentials: true。如果發(fā)送的是帶憑據(jù)的請求,而服務(wù)器中的響應(yīng)沒有包含這個頭部,那么JS獲取不到這個響應(yīng)中的信息。

跨瀏覽器的CORS

function createCORSRequest(method, url){
    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;
}
var request = createCORSRequest("get", "http://www.baidu.com/");
if (request){
    request.onload = function(){
        alert(request.responseText);
    };
    request.send();
}

其它跨域技術(shù)

在CORS出現(xiàn)之前,開發(fā)人員通過各種hack方式來實現(xiàn)跨域Ajax。

圖像Ping

這個利用的是一個網(wǎng)頁可以從任何地方加載圖像,而不用擔(dān)心跨域的問題。通過向一個URL請求圖片的方式,可以向服務(wù)器單向使用GET傳送參數(shù),由于img元素的本身限制,并不能獲取服務(wù)器發(fā)來的除圖像以外的數(shù)據(jù)(響應(yīng)文本)。只能通過監(jiān)聽load和error事件知道響應(yīng)何時收到。

var img = new Image();
img.onload = img.onerror = function(){
    alert("Done!");
};
img.src = "http://www.example.com/test?name=Nicholas";

響應(yīng)從圖片對象的src被設(shè)置時就開始了。
這個最大的用處就是跟蹤用戶點擊或廣告曝光次數(shù),網(wǎng)頁被打開了就使用img向紀(jì)錄服務(wù)器發(fā)送個規(guī)定的參數(shù),簡單可靠。
不過只能使用GET方法和無法獲得響應(yīng)文本是其局限。

JSONP

JSON with padding參數(shù)式JSON
JSONP利用動態(tài)script元素從其他域中加載資源,將服務(wù)器傳回的數(shù)據(jù)以JSON格式傳入一個回調(diào)函數(shù)中,形式就像這樣:

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

在實際使用時先創(chuàng)建一個用于處理數(shù)據(jù)的回調(diào)函數(shù),創(chuàng)建一個script對象,將回調(diào)函數(shù)的函數(shù)名作為其src的URL的一個參數(shù)傳遞給服務(wù)器端,服務(wù)器端根據(jù)這個URL中的參數(shù)們?nèi)〉庙憫?yīng)的數(shù)據(jù),并作為函數(shù)參數(shù)塞到回調(diào)函數(shù)中,返回一個像上面形式的對回調(diào)函數(shù)的調(diào)用。這是一個可執(zhí)行的JS,被放在了一個動態(tài)創(chuàng)建的script元素中,當(dāng)你把這個元素插入文檔,就相當(dāng)于執(zhí)行了這個有服務(wù)器數(shù)據(jù)作為參數(shù)的回調(diào)函數(shù)。

function handleResponse(response){
    alert("You re at IP address " + response.ip + ", which is in " +
        response.city + ", " + response.region_name);
}
var script = document.createElement("script");
script.src = "http://freegeoip.net/json/?callback=handleResponse";
document.body.insertBefore(script, document.body.firstChild);

這個就可以實現(xiàn)瀏覽器和服務(wù)器間的雙向通信了,不過有兩點問題:

  • 必須確保你請求的Web服務(wù)是可靠的,否則就是你親手給惡意代碼提供了執(zhí)行的機會
  • 對于確定何時接到請求或請求何時失敗并不好判斷,script元素在HTML5規(guī)范中是有error事件的,不過沒人實現(xiàn),現(xiàn)在一個比較笨的解決辦法是使用計時器手動檢測請求超時

Comet

Comet是一種服務(wù)器像瀏覽器推送數(shù)據(jù)的技術(shù)??梢宰屝畔⒔鯇崟r的被推送到頁面上。有兩種實現(xiàn)Comet的方式,長輪詢和流。
長輪詢
頁面發(fā)起一個到服務(wù)器的請求,服務(wù)器連接一直打開,知道有數(shù)據(jù)可發(fā)送,瀏覽器接收完數(shù)據(jù)后關(guān)閉該連接,發(fā)起一個新的請求。

HTTP流的實現(xiàn)方式則不同,在頁面的整個生命周期內(nèi)只會有一個HTTP連接。瀏覽器向服務(wù)器發(fā)送一個請求,服務(wù)器保持連接打開,周期性的向瀏覽器發(fā)送數(shù)據(jù)。一般來說,都是把新的數(shù)據(jù)加到之前輸出緩存的末尾再重新都發(fā)一遍。
通過監(jiān)聽readystatechange事件,當(dāng)readyState為3時就代表數(shù)據(jù)都接收到了。隨著不斷從服務(wù)器端接收到數(shù)據(jù),readyState會周期性的變?yōu)?。這時就可以讀取responseText中的數(shù)據(jù),并與上次接收到的做比對,獲取新的數(shù)據(jù)。

function createStreamingClient(url, progress, finished){
    var xhr = new XMLHttpRequest(),
        received = 0;
    xhr.open("get", url, true);
    xhr.onreadystatechange = function(){
        var result;
        if (xhr.readyState == 3){
            //     數(shù)     數(shù)
            result = xhr.responseText.substring(received);
            received += result.length;
            //   progress    數(shù)
            progress(result);
        } else if (xhr.readyState == 4){
            finished(xhr.responseText);
        }
    };
    xhr.send(null);
    return xhr;
}
var client = createStreamingClient("streaming.php", function(data){
                alert("Received: " + data);
            }, function(data){
                alert("Done!"+ data);
            });

Comet連接比較容易出錯,不過大家都看好這項技術(shù),為了簡化這項技術(shù)的使用成本,提高可靠性,又有兩個新的接口出現(xiàn)了。服務(wù)器發(fā)送事件(Server-Sent Events,SSE)和Web Socket。

服務(wù)器發(fā)送事件

Server-Sent Events,SSE,這是圍繞只讀Comet推出的API,用于創(chuàng)建到服務(wù)器的單向連接。服務(wù)器通過這個連接可以發(fā)送任意數(shù)量的數(shù)據(jù)。服務(wù)器響應(yīng)的MIME類型必須是text/event-stream,并且是瀏覽器中的JS能解析的格式輸出。SSE支持短輪詢,長輪詢,HTTP流。并且在斷開連接時自動確定何時重連。
支持SSE的瀏覽器有:Firefox 6+ Safari 5+ Opera 11+ Chrome iOS 4+版 Safari。
SSE API
首先新建一個EventSource對象,參數(shù)為入口點URL,這個URL要與創(chuàng)建對象的頁面同源(相同URL模式,域,及端口)。EventSource對象的readyState屬性:

  • 0:正在連接服務(wù)器
  • 1:打開了連接
  • 2:關(guān)閉了連接。

三個事件:

  • open建立連接時
  • message收到新服務(wù)器事件時
  • error連接錯誤時

在連接斷開時會自己重新連接。這就非常適合長輪詢,HTTP流。
想要手動斷開,有close方法。

var source = new EventSource("myevents.php");
source.onmessage = function(event){ 
    var data = event.data; 
};
source.close();

事件流

服務(wù)器事件會通過一個持久的HTTP響應(yīng)發(fā)送,這個響應(yīng)的MIME類型為text/event-stream,格式為純文本。最簡單的情況是每個數(shù)據(jù)項都有前綴data:

data: foo

data: bar

data: foo
data: bar

對應(yīng)的message事件有3個,event.data的值分別為foo,bar,foo/bar。在服務(wù)器端要注意,只有data:后面有空行時才回觸發(fā)message事件。

data: foo
id: 1

id: 2
data: foo
data: bar

id可以將事件與一個ID綁定,id的位置可以在data的前后。如果連接斷開,會向服務(wù)器發(fā)送Last-Event-ID頭部,以便服務(wù)器知道下次該發(fā)什么。

Web Socket

其目標(biāo)是在一個單獨的持久連接上提供一個全雙工的雙向通信。在Web Socket建立以后,會有一個HTTP請求發(fā)送到服務(wù)器,在取得響應(yīng)后,連接會開始使用Web Socket協(xié)議。其URL模式為ws:// , wss://。
使用Web Socket意味著更小的開銷,但是同時這個協(xié)議的問題還在不斷的被發(fā)現(xiàn),現(xiàn)在支持這個協(xié)議的有Firefox 6+ Safari 5+ Chrome iOS 4+版 Safari。
Web Sockets API
Web Socket的構(gòu)造函數(shù)只接受絕對URL。并不要求同源,因為服務(wù)器可以判斷并決定連接可以獲取什么樣的資源。
實例化后,連接馬上會創(chuàng)建。readyState:

  • WebSocket.OPENING (0)
  • WebSocket.OPEN (1)
  • WebSocket.CLOSING (2)
  • WebSocket.CLOSE (3)

關(guān)閉時使用close()
發(fā)送和接收
發(fā)送只能是純文本數(shù)據(jù),所以復(fù)雜的數(shù)據(jù)結(jié)構(gòu)要序列化。

var socket = new WebSocket("ws://www.example.com/server.php");
var message = {
    time: new Date(),
    text: "Hello world!",
    clientId: "asdfp8734rew"
};
socket.send(JSON.stringify(message));

接受時會觸發(fā)message事件

socket.onmessage = function(event){
    var data = event.data;
};

其他事件
open,error,close

安全

跨站請求偽造是Ajax遇到的最大問題,如果你可以通過Ajax的URL獲取,直接輸URL也可以。
所以我們要確認(rèn)請求發(fā)送者是否有訪問資源的權(quán)限。有下列方式可以選擇:

  • SSL保護
  • 每次請求附帶算法計算的驗證碼

下面的方法沒用,很容易偽造:

  • 檢查URL是否可信
  • 基于cookie驗證

XHR對象本身提供了一些安全機制,open 方法其實可以傳用戶名和密碼??墒窃贘S中保存這些,用調(diào)試器一下就看到明文了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 國家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 12,522評論 6 13
  • ajax作為前端開發(fā)必需的基礎(chǔ)能力之一,你可能會使用它,但并不一定懂得其原理,以及更深入的服務(wù)器通信相關(guān)的知識。在...
    蕭玄辭閱讀 889評論 0 0
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,695評論 19 139
  • 本文詳細(xì)介紹了 XMLHttpRequest 相關(guān)知識,涉及內(nèi)容: AJAX、XMLHTTP、XMLHttpReq...
    semlinker閱讀 14,005評論 2 18
  • AJAX 原生js操作ajax 1.創(chuàng)建XMLHttpRequest對象 var xhr = new XMLHtt...
    碧玉含香閱讀 3,580評論 0 7

友情鏈接更多精彩內(nèi)容