XMLHttpRequest 對象php
瀏覽器與服務器之間,採用 HTTP 協議 通訊。html
用戶在瀏覽器地址欄鍵入一個網址,或者經過網頁表單向服務器提交內容,這時瀏覽器就會向服務器發出 HTTP 請求json
AJAX跨域
2005.02 提出的概念 ---- Asynchronous JavaScript and XML數組
經過 JavaScript 的異步通訊,從服務器獲取 XML 文檔從中提取數據,再更新當前網頁的對應部分,而不用刷新整個網頁瀏覽器
JavaScript 腳本發起 HTTP 通訊的代名詞服務器
也就是說,只要用腳本發起通訊,就能夠叫作 AJAX 通訊
網絡
1. 建立 XMLHttpRequest 實例app
var xhr = new XMLHttpRequest();異步
2. 發出 HTTP 請求
// 向指定的服務器網址,發出 GET 請求
xhr.open('GET', 'http://www.example.com/page.php', true);
3. 接收服務器傳回的數據
// 監聽通訊狀態(readyState
屬性)的變化
xhr.onreadystatechange = handleStateChange;
function handleStateChange(){... ...}
4. 更新網頁數據
// 一旦拿到服務器返回的數據,AJAX 不會刷新整個網頁,而是隻更新網頁裏面的相關部分,從而不打斷用戶正在作的事情
歸納爲: AJAX 經過原生的 XMLHttpRequest
對象發出 HTTP 請求,獲得服務器返回的數據後,再進行處理
注意:
如今,服務器返回的都是 JSON 格式的數據,XML 格式已通過時了
AJAX 這個名字已經成了一個通用名詞,字面含義已經消失了
XMLHttpRequest
對象是 AJAX 的主要接口,用於瀏覽器與服務器之間的通訊
不止 XML
和 Http
,實際可使用多種協議(如file
或ftp
)發送任何格式的數據(字符串、二進制)
AJAX 只能向同源網址(協議、域名、端口都相同)發出 HTTP 請求,若是發出跨域請求,就會報錯
使用實例的 abort() 方法,終止 XMLHttpRequest 請求,也會形成 readyState 屬性變化,致使調用 XMLHttpRequest.onreadystatechange 屬性
XMLHttpRequest 的實例屬性
該屬性只讀。它可能返回如下值。
0 表示 XMLHttpRequest 實例已經生成,可是實例的 open() 方法尚未被調用。
1 表示 open() 方法已經調用,可是實例的 send() 方法尚未調用
仍然可使用實例的 setRequestHeader() 方法,設定 HTTP 請求的頭信息。
2 表示實例的 send() 方法已經調用,而且服務器返回的頭信息和狀態碼已經收到。
3 表示正在接收服務器傳來的數據體(body 部分)
這時,若是實例的 responseType 屬性等於 text 或者空字符串
responseText 屬性就會包含已經收到的部分信息。
4 表示服務器返回的數據已經徹底接收,或者本次接收已經失敗
var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { handler(xhr.response); } }
該屬性只讀
它多是任何數據類型,好比字符串、對象、二進制對象等等
表示服務器返回數據的類型。
這個屬性是可寫的,能夠在調用 open() 方法以後、調用 send() 方法以前,設置這個屬性的值,告訴服務器返回指定類型的數據
若是 responseType 設爲空字符串,就等同於默認值 text
適合大多數狀況,並且直接處理文本也比較方便
var xhr = new XMLHttpRequest(); xhr.open('GET', '/path/to/image.png', true); xhr.responseType = 'blob'; xhr.onload = function(e) { if (this.status === 200) { var blob = new Blob([xhr.response], {type: 'image/png'}); // 或者 var blob = xhr.response; } }; xhr.send();
適合讀取二進制數據,好比圖片文件
var xhr = new XMLHttpRequest(); xhr.open('GET', '/path/to/image.png', true); xhr.responseType = 'blob'; xhr.onload = function(e) { if (this.status === 200) { var blob = new Blob([xhr.response], {type: 'image/png'}); // 或者 var blob = xhr.response; } }; xhr.send();
適合返回 HTML / XML 文檔的狀況
這意味着,對於那些打開 CORS 的網站,能夠直接用 Ajax 抓取網頁
而後不用解析 HTML 字符串,直接對抓取回來的數據進行 DOM 操做
若是將這個屬性設爲json,瀏覽器就會自動對返回數據調用 JSON.parse() 方法
也就是說,從 xhr.response 屬性(注意,不是xhr.responseText屬性)獲得的不是文本,而是一個 JSON 對象
若是本次請求沒有成功或者數據不完整,該屬性等於null
可是,若是 responseType 屬性等於 text 或空字符串
在請求沒有結束以前(readyState 等於 3 的階段)
XMLHttpRequest.response 屬性包含服務器已經返回的部分數據
該屬性爲只讀
只有 HTTP 請求完成接收之後,該屬性纔會包含完整的數據
var xhr = new XMLHttpRequest(); xhr.open('GET', '/server', true); xhr.responseType = 'text'; xhr.onload = function () { if (xhr.readyState === 4 && xhr.status === 200) { console.log(xhr.responseText); } }; xhr.send(null);
XMLHttpRequest.responseXML ---- 直接解析後的文檔 DOM 樹
生效的前提是 HTTP 迴應的 Content-Type 頭信息等於 text/xml 或 application/xml
在發送請求前,XMLHttpRequest.responseType 屬性要設爲 document
若是 HTTP 迴應的 Content-Type 頭信息不等於 text/xml 和 application/xml ,
可是又想從 responseXML 拿到數據(即把數據按照 DOM 格式解析),
那麼須要手動調用 XMLHttpRequest.overrideMimeType() 方法,強制進行 XML 解析
var xhr = new XMLHttpRequest(); xhr.open('GET', '/server', true); xhr.responseType = 'document'; xhr.overrideMimeType('text/xml'); // 強制進行 XML 解析 xhr.onload = function () { if (xhr.readyState === 4 && xhr.status === 200) { console.log(xhr.responseXML); // 獲得的數據,是直接解析後的文檔 DOM 樹 } }; xhr.send(null);
返回從服務器接收到的 HTML 或 XML 文檔對象,該屬性爲只讀。
若是本次請求沒有成功,或者收到的數據不能被解析爲 XML 或 HTML,該屬性等於 null
XMLHttpRequest.responseURL ---- 字符串,表示發送數據的服務器的網址
var xhr = new XMLHttpRequest( xhr.open('GET', 'http://example.com/test', true); xhr.onload = function () { // 返回 http://example.com/test console.log(xhr.responseURL); }; xhr.send(null);
這個屬性的值 與 open()方 法指定的請求網址不必定相同
若是服務器端發生跳轉,這個屬性返回最後實際返回數據的網址
另外,若是原始 URL 包括錨點(fragment),該屬性會把錨點剝離
XMLHttpRequest.status ---- 整數,表示服務器迴應的 HTTP 狀態碼
通常來講,若是通訊成功的話,這個狀態碼是200;
若是服務器沒有返回狀態碼,那麼這個屬性默認是 200。
請求發出以前,該屬性爲 0。該屬性只讀
XMLHttpRequest.statusText ---- 返回一個字符串,表示服務器發送的狀態提示
該屬性只讀,包含整個狀態信息,好比 「OK」 和 「Not Found」
在請求發送以前(即調用 open() 方法以前),該屬性的值是空字符串
若是服務器沒有返回狀態提示,該屬性的值默認爲"「OK」
XMLHttpRequest.timeout ---- 整數,表示多少毫秒後,若是請求仍然沒有獲得結果,就會自動終止
若是該屬性等於 0 ,就表示沒有時間限制
XMLHttpRequestEventTarget.ontimeout ---- 用於設置一個監聽函數,若是發生 timeout 事件,就會執行這個監聽函數
var xhr = new XMLHttpRequest(); var url = '/server'; xhr.ontimeout = function () { console.error('The request for ' + url + ' timed out.'); }; xhr.onload = function() { if (xhr.readyState === 4) { if (xhr.status === 200) { // 處理服務器返回的數據 } else { console.error(xhr.statusText); } } }; xhr.open('GET', url, true); // 指定 10 秒鐘超時 xhr.timeout = 10 * 1000; xhr.send(null);
XMLHttpRequest.withCredentials ---- 布爾值,表示跨域請求時,用戶信息(好比 Cookie 和認證的 HTTP 頭信息)是否會包含在請求之中
默認爲 false,即向 example.com 發出跨域請求時,不會發送example.com設置在本機上的 Cookie(若是有的話)
withCredentials屬性打開的話,跨域請求不只會發送 Cookie,還會設置遠程主機指定的 Cookie
若是須要跨域 AJAX 請求發送 Cookie,須要 withCredentials 屬性設爲true。注意,同源的請求不須要設置這個屬性
var xhr = new XMLHttpRequest(); xhr.open('GET', 'http://example.com/', true); xhr.withCredentials = true; xhr.send(null);
爲了讓這個屬性生效,服務器必須顯式返回Access-Control-Allow-Credentials這個頭信息
Access-Control-Allow-Credentials: true
XMLHttpRequest 事件監聽函數
.onloadstart loadstart 事件 (HTTP 請求發出)的監聽函數
.onprogress progress 事件 (正在發送和加載數據)的監聽函數
.onabort abort 事件 (請求停止,好比用戶調用了abort()方法)的監聽函數
.onerror error 事件 (請求失敗)的監聽函數
注意,若是發生網絡錯誤(好比服務器沒法連通),onerror 事件沒法獲取報錯信息
也就是說,可能沒有錯誤對象,因此這樣只能顯示報錯的提示
.onload load 事件 (請求成功完成)的監聽函數
.ontimeout timeout 事件 (用戶指定的時限超過了,請求還未完成)的監聽函數
.onloadend loadend 事件 (請求完成,無論成功或失敗)的監聽函數
全部這些監聽函數裏面,只有 progress 事件的監聽函數有事件對象參數,該對象有三個屬性
loaded 返回 已經傳輸的數據量
total 屬性返回 總的數據量
lengthComputable 返回一個布爾值,表示加載的進度是否能夠計算
AJAX 文件上傳
發送文件之後,經過 XMLHttpRequest.upload 屬性能夠獲得一個對象,經過觀察這個對象,能夠得知上傳的進展
主要方法就是監聽這個對象的各類事件:loadstart、loadend、load、abort、error、progress、timeout
假定網頁上有一個 <progress> 元素
<progress min="0" max="100" value="0">0% complete</progress>
指定progress事件的監聽函數,便可得到上傳的進度
function upload(blobOrFile) { var xhr = new XMLHttpRequest(); xhr.open('POST', '/server', true); xhr.onload = function (e) {}; var progressBar = document.querySelector('progress'); xhr.upload.onprogress = function (e) { if (e.lengthComputable) { progressBar.value = (e.loaded / e.total) * 100; // 兼容不支持 <progress> 元素的老式瀏覽器 progressBar.textContent = progressBar.value; } }; xhr.send(blobOrFile); } upload(new Blob(['hello world'], {type: 'text/plain'}));
XMLHttpRequest 的實例方法
XMLHttpRequest.open()
用於指定 HTTP 請求的參數,或者說初始化 XMLHttpRequest 實例對象。
它一共能夠接受五個參數
void open( string method, // method:表示 HTTP 動詞方法,好比 GET、POST、PUT、DELETE、HEAD等。 string url, // 表示請求發送目標 URL optional boolean async, // 布爾值,表示請求是否爲異步,默認爲 true。該參數可選。 // 若是設爲 false,則 send() 方法只有等到收到服務器返回告終果,纔會進行下一步操做。 // 因爲同步 AJAX 請求會形成瀏覽器失去響應,許多瀏覽器已經禁止在主線程使用,只容許 Worker 裏面使用。 // 因此,這個參數輕易不該該設爲 false optional string user, // 表示用於認證的用戶名,默認爲空字符串。該參數可選 optional string password // 表示用於認證的密碼,默認爲空字符串。該參數可選 );
若是對使用過 open()
方法的 AJAX 請求,再次使用這個方法,等同於調用 abort()
,即終止請求
XMLHttpRequest.send()
用於實際發出 HTTP 請求。
它的參數是可選的,
若是不帶參數,就表示 HTTP 請求只有一個 URL,沒有數據體,典型例子就是 GET 請求
var xhr = new XMLHttpRequest(); xhr.open('GET', 'http://www.example.com/?id=' + encodeURIComponent(id), // GET請求的參數,做爲查詢字符串附加在 URL 後面 true ); xhr.send(null);
若是帶有參數,就表示除了頭信息,還帶有包含具體數據的信息體,典型例子就是 POST 請求
var xhr = new XMLHttpRequest(); var data = 'email=' + encodeURIComponent(email) + '&password=' + encodeURIComponent(password); xhr.open('POST', 'http://www.example.com', true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send(data);
// 注意,XMLHttpRequest 全部的監聽事件,都必須在 send()
方法調用以前設定
參數就是發送的數據。多種格式的數據,均可以做爲它的參數
void send();
void send(ArrayBufferView data);
void send(Blob data); // 若是發送二進制數據,最好是發送ArrayBufferView或Blob對象,這使得經過 Ajax 上傳文件成爲可能
void send(Document data); // 若是send()發送 DOM 對象,在發送以前,數據會先被串行化
void send(String data);
void send(FormData data);
var formData = new FormData(); formData.append('username', '張三'); formData.append('email', 'zhangsan@example.com'); formData.append('birthDate', 1940); var xhr = new XMLHttpRequest(); xhr.open('POST', '/register'); xhr.send(formData);
<form id='registration' name='registration' action='/register'> <input type='text' name='username' value='張三'> <input type='email' name='email' value='zhangsan@example.com'> <input type='number' name='birthDate' value='1940'> <input type='submit' onclick='return sendForm(this.form);'> </form>
function sendForm(form) { var formData = new FormData(form); formData.append('csrf', 'e69a18d7db1286040586e6da1950128c'); var xhr = new XMLHttpRequest(); xhr.open('POST', form.action, true); xhr.onload = function() { // ... }; xhr.send(formData); return false; } var form = document.querySelector('#registration'); sendForm(form);
XMLHttpRequest.setRequestHeader()
用於設置瀏覽器發送的 HTTP 請求的頭信息。
xhr.setRequestHeader('Content-Type', 'application/json'); xhr.setRequestHeader('Content-Length', JSON.stringify(data).length); xhr.send(JSON.stringify(data));
首先設置頭信息 Content-Type,表示發送 JSON 格式的數據
而後設置 Content-Length,表示數據長度
最後發送 JSON 數據。
該方法必須在open()以後、send()以前調用。
該方法接受兩個參數
第一個參數是字符串,表示頭信息的字段名
第二個參數是字段值
若是該方法屢次調用,設定同一個字段,則每一次調用的值會被合併成一個單一的值發送。
XMLHttpRequest.overrideMimeType()
用來指定 MIME 類型,覆蓋服務器返回的真正的 MIME 類型,從而讓瀏覽器進行不同的處理。
舉例來講,服務器返回的數據類型是 text/xml,因爲種種緣由瀏覽器解析不成功報錯,這時就拿不到數據了。
爲了拿到原始數據,咱們能夠把 MIME 類型改爲 text/plain,這樣瀏覽器就不會去自動解析,從而咱們就能夠拿到原始文本了
xhr.overrideMimeType('text/plain')
修改服務器返回的數據類型,不是正常狀況下應該採起的方法。
若是但願服務器返回指定的數據類型,能夠用 responseType 屬性告訴服務器,就像下面的例子。
只有在服務器沒法返回某種數據類型時,才使用 overrideMimeType() 方法
var xhr = new XMLHttpRequest(); xhr.onload = function(e) { var arraybuffer = xhr.response; // ... } xhr.open('GET', url); xhr.responseType = 'arraybuffer'; xhr.send();
XMLHttpRequest.getResponseHeader()
返回 HTTP 頭信息指定字段的值
若是尚未收到服務器迴應或者指定字段不存在,返回 null。
function getHeaderTime() { console.log(this.getResponseHeader("Last-Modified")); } var xhr = new XMLHttpRequest(); xhr.open('HEAD', 'yourpage.html'); xhr.onload = getHeaderTime; xhr.send();
該方法的參數不區分大小寫
若是有多個字段同名,它們的值會被鏈接爲一個字符串,每一個字段之間使用 「逗號+空格」 分隔
XMLHttpRequest.getAllResponseHeaders()
返回一個字符串,表示服務器發來的全部 HTTP 頭信息。
格式爲字符串,每一個頭信息之間使用 CRLF
分隔(回車+換行)
若是沒有收到服務器迴應,該屬性爲null
。
若是發生網絡錯誤,該屬性爲空字符串
var xhr = new XMLHttpRequest(); xhr.open('GET', 'foo.txt', true); xhr.send(); xhr.onreadystatechange = function () { if (this.readyState === 4) { var headers = xhr.getAllResponseHeaders(); } }
上面代碼用於獲取服務器返回的全部頭信息。它多是下面這樣的字符串
date Fri, 08 Dec 2017 21:04:30 GMT\r\n content-encoding ------------ gzip\r\n x-content-type-options nosniff\r\n server ---------------------- meinheld/0.6.1\r\n x-frame-options DENY\r\n content-type --------------- text/html; charset=utf-8\r\n connection keep-alive\r\n strict-transport-security -- max-age=63072000\r\n vary Cookie, Accept-Encoding\r\n content-length ------------- 6502\r\n x-xss-protection 1; mode=block\r\n
而後,對這個字符串 header 進行處理
var arr = headers.trim().split(/[\r\n]+/); var headerMap = {}; arr.forEach(function (line) { var parts = line.split(': '); var header = parts.shift(); var value = parts.join(': '); headerMap[header] = value; }); headerMap['content-length'] // "6502"
XMLHttpRequest.abort()
用來終止已經發出的 HTTP 請求。
調用這個方法之後,readyState 屬性變爲 4,status 屬性變爲0
舉個例子: 發出5秒以後,終止一個 AJAX 請求
var xhr = new XMLHttpRequest(); xhr.open('GET', 'http://www.example.com/page.php', true); setTimeout(function () { if (xhr) { xhr.abort(); xhr = null; } }, 5000);
重要的事件
readyStateChange 事件
readyState 屬性的值發生改變,就會觸發 readyStateChange 事件
咱們能夠經過onReadyStateChange屬性,指定這個事件的監聽函數,對不一樣狀態進行不一樣處理
尤爲是當狀態變爲 4 的時候,表示通訊成功,這時回調函數就能夠處理服務器傳送回來的數據
progress 事件
上傳文件時,XMLHTTPRequest 實例對象自己和實例的 upload 屬性,都有一個 progress 事件,會不斷返回上傳的進度
var xhr = new XMLHttpRequest(); function updateProgress (oEvent) { if (oEvent.lengthComputable) { var percentComplete = oEvent.loaded / oEvent.total; } else { console.log('沒法計算進展'); } } xhr.addEventListener('progress', updateProgress); xhr.open();
load 事件 表示服務器傳來的數據接收完畢
error 事件 表示請求出錯
abort 事件 表示請求被中斷(好比用戶取消請求)
var xhr = new XMLHttpRequest(); xhr.addEventListener('load', transferComplete); xhr.addEventListener('error', transferFailed); xhr.addEventListener('abort', transferCanceled); xhr.open(); function transferComplete() { console.log('數據接收完畢'); } function transferFailed() { console.log('數據接收出錯'); } function transferCanceled() { console.log('用戶取消接收'); }
Navigator.sendBeacon() 用戶卸載網頁的時候,有時須要向服務器發一些數據
XMLhttpRequest對象是異步發送,極可能在它即將發送的時候,頁面已經卸載了
這個方法仍是異步發出請求,可是請求與當前頁面脫鉤,做爲瀏覽器的任務,所以能夠保證會把數據發出去,不拖延卸載流程
window.addEventListener('unload', logData, false); function logData() { navigator.sendBeacon('/log', analyticsData); }
第一個參數是目標服務器的 URL
第二個參數是所要發送的數據(可選),能夠是任意類型(字符串、表單對象、二進制對象等等)
成功發送數據 返回 true,不然返回爲 false
發送數據的 HTTP 方法是 POST,能夠跨域,相似於表單提交數據。它不能指定回調函數
// HTML 代碼以下 // <body onload="analytics('start')" onunload="analytics('end')"> function analytics(state) { if (!navigator.sendBeacon)
return; var URL = 'http://example.com/analytics'; var data = 'state=' + state + '&location=' + window.location; navigator.sendBeacon(URL, data); }