<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                Ajax指的是不刷新頁面,發出異步請求,向服務器端要求數據,然后再進行處理的方法。 [TOC] ## XMLHttpRequest對象 XMLHttpRequest對象用于從JavaScript發出HTTP請求,下面是典型用法。 ~~~ // 新建一個XMLHttpRequest實例對象 var xhr = new XMLHttpRequest(); // 指定通信過程中狀態改變時的回調函數 xhr.onreadystatechange = function(){ // 通信成功時,狀態值為4 var completed = 4; if(xhr.readyState === completed){ if(xhr.status === 200){ // 處理服務器發送過來的數據 }else{ // 處理錯誤 } } }; // open方式用于指定HTTP動詞、請求的網址、是否異步 xhr.open('GET', '/endpoint', true); // 發送HTTP請求 xhr.send(null); ~~~ ### Open() open方法用于指定發送HTTP請求的參數,它有三個參數如下: * 發送方法,一般來說為“GET”、“POST”、“PUT”和“DELETE”中的一個值。 * 網址。 * 是否異步,true表示異步,false表示同步。 下面發送POST請求的例子。 ~~~ xhr.open('POST', encodeURI('someURL')); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.onload = function() {}; xhr.send(encodeURI('dataString')); ~~~ 上面方法中,open方法向指定URL發出POST請求,send方法送出實際的數據。 ### setRequestHeader() setRequestHeader方法用于設置HTTP請求的頭信息。 ### send() send方法用于實際發出HTTP請求。如果不帶參數,就表示HTTP請求只包含頭信息,也就是只有一個URL,典型例子就是GET請求;如果帶有參數,就表示除了頭信息,還帶有包含具體數據的信息體,典型例子就是POST請求。 在XHR 2之中,send方法可以發送許多類型的數據。 ~~~ void send(); void send(ArrayBuffer data); void send(Blob data); void send(Document data); void send(DOMString data); void send(FormData data); ~~~ Blob類型可以用來發送二進制數據,這使得通過Ajax上傳文件成為可能。 FormData類型可以用于構造表單數據。 ~~~ var formData = new FormData(); formData.append('username', '張三'); formData.append('email', 'zhangsan@example.com'); formData.append('birthDate', 1940); xhr.send(formData); ~~~ 上面的代碼構造了一個formData對象,然后使用send方法發送。它的效果與點擊下面表單的submit按鈕是一樣的。 ~~~ <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> ~~~ FormData對象還可以對現有表單添加數據,這為我們操作表單提供了極大的靈活性。 ~~~ 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(e) { // ... }; xhr.send(formData); return false; } var form = document.querySelector('#registration'); sendForm(form); ~~~ FormData對象也能用來模擬File控件,進行文件上傳。 ~~~ function uploadFiles(url, files) { var formData = new FormData(); for (var i = 0, file; file = files[i]; ++i) { formData.append(file.name, file); } var xhr = new XMLHttpRequest(); xhr.open('POST', url, true); xhr.onload = function(e) { ... }; xhr.send(formData); // multipart/form-data } document.querySelector('input[type="file"]').addEventListener('change', function(e) { uploadFiles('/server', this.files); }, false); ~~~ ### readyState屬性和readyStateChange事件 在通信過程中,每當發生狀態變化的時候,readyState屬性的值就會發生改變。 這個值每一次變化,都會觸發readyStateChange事件。我們可以指定這個事件的回調函數,對不同狀態進行不同處理。尤其是當狀態變為4的時候,表示通信成功,這時回調函數就可以處理服務器傳送回來的數據。 ### progress事件 上傳文件時,XMLHTTPRequest對象的upload屬性有一個progress,會不斷返回上傳的進度。 假定網頁上有一個progress元素。 ~~~ <progress min="0" max="100" value="0">0% complete</progress> ~~~ 文件上傳時,對upload屬性指定progress事件回調函數,即可獲得上傳的進度。 ~~~ function upload(blobOrFile) { var xhr = new XMLHttpRequest(); xhr.open('POST', '/server', true); xhr.onload = function(e) { ... }; // Listen to the upload progress. var progressBar = document.querySelector('progress'); xhr.upload.onprogress = function(e) { if (e.lengthComputable) { progressBar.value = (e.loaded / e.total) * 100; progressBar.textContent = progressBar.value; // Fallback for unsupported browsers. } }; xhr.send(blobOrFile); } upload(new Blob(['hello world'], {type: 'text/plain'})); ~~~ 下面是一個上傳ArrayBuffer對象的例子。 ~~~ function sendArrayBuffer() { var xhr = new XMLHttpRequest(); xhr.open('POST', '/server', true); xhr.onload = function(e) { ... }; var uInt8Array = new Uint8Array([1, 2, 3]); xhr.send(uInt8Array.buffer); } ~~~ ### 服務器返回的信息 (1)status屬性 status屬性表示返回的HTTP狀態碼。一般來說,如果通信成功的話,這個狀態碼是200。 (2)responseText屬性 responseText屬性表示服務器返回的文本數據。 ### setRequestHeader方法 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數據。 ### overrideMimeType方法 該方法用來指定服務器返回數據的MIME類型。 傳統上,如果希望從服務器取回二進制數據,就要使用這個方法,人為將數據類型偽裝成文本數據。 ~~~ var xhr = new XMLHttpRequest(); xhr.open('GET', '/path/to/image.png', true); // 強制將MIME改為文本類型 xhr.overrideMimeType('text/plain; charset=x-user-defined'); xhr.onreadystatechange = function(e) { if (this.readyState == 4 && this.status == 200) { var binStr = this.responseText; for (var i = 0, len = binStr.length; i < len; ++i) { var c = binStr.charCodeAt(i); var byte = c & 0xff; // 去除高位字節,留下低位字節 } } }; xhr.send(); ~~~ 上面代碼中,因為傳回來的是二進制數據,首先用xhr.overrideMimeType方法強制改變它的MIME類型,偽裝成文本數據。字符集必需指定為“x-user-defined”,如果是其他字符集,瀏覽器內部會強制轉碼,將其保存成UTF-16的形式。字符集“x-user-defined”其實也會發生轉碼,瀏覽器會在每個字節前面再加上一個字節(0xF700-0xF7ff),因此后面要對每個字符進行一次與運算(&),將高位的8個位去除,只留下低位的8個位,由此逐一讀出原文件二進制數據的每個字節。 這種方法很麻煩,在XMLHttpRequest版本升級以后,一般采用下面的指定responseType的方法。 ### responseType屬性 XMLHttpRequest對象有一個responseType屬性,用來指定服務器返回數據(xhr.response)的類型。 XHR 2允許用戶自行設置這個屬性,也就是指定返回數據的類型,可以設置如下的值: * 'text':返回類型為字符串,這是默認值。 * 'arraybuffer':返回類型為ArrayBuffer。 * 'blob':返回類型為Blob。 * 'document':返回類型為Document。 * 'json':返回類型為JSON object。 text類型適合大多數情況,而且直接處理文本也比較方便,document類型適合返回XML文檔的情況,blob類型適合讀取二進制數據,比如圖片文件。 ~~~ 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([this.response], {type: 'image/png'}); // ... } }; xhr.send(); ~~~ 如果將這個屬性設為ArrayBuffer,就可以按照數組的方式處理二進制數據。 ~~~ var xhr = new XMLHttpRequest(); xhr.open('GET', '/path/to/image.png', true); xhr.responseType = 'arraybuffer'; xhr.onload = function(e) { var uInt8Array = new Uint8Array(this.response); for (var i = 0, len = binStr.length; i < len; ++i) { // var byte = uInt8Array[i]; } }; xhr.send(); ~~~ 如果將這個屬性設為“json”,支持JSON的瀏覽器(Firefox>9,chrome>30),就會自動對返回數據調用JSON.parse() 方法。也就是說,你從xhr.response屬性(注意,不是xhr.responseText屬性)得到的不是文本,而是一個JSON對象。 XHR2支持Ajax的返回類型為文檔,即xhr.responseType="document" 。這意味著,對于那些打開CORS的網站,我們可以直接用Ajax抓取網頁,然后不用解析HTML字符串,直接對XHR回應進行DOM操作。 ## 文件上傳 通常,我們使用file控件實現文件上傳。 ~~~ <form id="file-form" action="handler.php" method="POST"> <input type="file" id="file-select" name="photos[]" multiple/> <button type="submit" id="upload-button">上傳</button> </form> ~~~ 上面HTML代碼中,file控件的multiple屬性,指定可以一次選擇多個文件;如果沒有這個屬性,則一次只能選擇一個文件。 file對象的files屬性,返回一個FileList對象,包含了用戶選中的文件。 ~~~ var fileSelect = document.getElementById('file-select'); var files = fileSelect.files; ~~~ 然后,新建一個FormData對象的實例,用來模擬發送到服務器的表單數據,把選中的文件添加到這個對象上面。 ~~~ var formData = new FormData(); for (var i = 0; i < files.length; i++) { var file = files[i]; if (!file.type.match('image.*')) { continue; } formData.append('photos[]', file, file.name); } ~~~ 上面代碼中的FormData對象的append方法,除了可以添加文件,還可以添加二進制對象(Blob)或者字符串。 ~~~ // Files formData.append(name, file, filename); // Blobs formData.append(name, blob, filename); // Strings formData.append(name, value); ~~~ append方法的第一個參數是表單的控件名,第二個參數是實際的值,第三個參數是可選的,通常是文件名。 最后,使用Ajax方法向服務器上傳文件。 ~~~ var xhr = new XMLHttpRequest(); xhr.open('POST', 'handler.php', true); xhr.onload = function () { if (xhr.status !== 200) { alert('An error occurred!'); } }; xhr.send(formData); ~~~ 目前,各大瀏覽器(包括IE 10)都支持Ajax上傳文件。 除了使用FormData接口上傳,也可以直接使用File API上傳。 ~~~ var file = document.getElementById('test-input').files[0]; var xhr = new XMLHttpRequest(); xhr.open('POST', 'myserver/uploads'); xhr.setRequestHeader('Content-Type', file.type); xhr.send(file); ~~~ 可以看到,上面這種寫法比FormData的寫法,要簡單很多。 ## JSONP JSONP是一種常見做法,用于服務器與客戶端之間的數據傳輸,主要為了規避瀏覽器的同域限制。因為Ajax只能向當前網頁所在的域名發出HTTP請求(除非使用下文要提到的CORS,但并不是所有服務器都支持CORS),所以JSONP就采用在網頁中動態插入script元素的做法,向服務器請求腳本文件。 ~~~ function addScriptTag(src){ var script = document.createElement('script'); script.setAttribute("type","text/javascript"); script.src = src; document.body.appendChild(script); } window.onload = function(){ addScriptTag("http://example.com/ip?callback=foo"); } function foo(data) { console.log('Your public IP address is: ' + data.ip); }; ~~~ 上面代碼使用了JSONP,運行以后當前網頁就可以直接處理example.com返回的數據了。 由于script元素返回的腳本文件,是直接作為代碼運行的,不像Ajax請求返回的是JSON字符串,需要用JSON.parse方法將字符串轉為JSON對象。于是,為了方便起見,許多服務器支持JSONP指定回調函數的名稱,直接將JSON數據放入回調函數的參數,如此一來就省略了將字符串解析為JSON對象的步驟。 請看下面的例子,假定訪問?[http://example.com/ip](http://example.com/ip)?,返回如下JSON數據: ~~~ {"ip":"8.8.8.8"} ~~~ 現在服務器允許客戶端請求時使用callback參數指定回調函數。訪問?[http://example.com/ip?callback=foo](http://example.com/ip?callback=foo)?,返回的數據變成: ~~~ foo({"ip":"8.8.8.8"}) ~~~ 這時,如果客戶端定義了foo函數,該函數就會被立即調用,而作為參數的JSON數據被視為JavaScript對象,而不是字符串,因此避免了使用JSON.parse的步驟。 ~~~ function foo(data) { console.log('Your public IP address is: ' + data.ip); }; ~~~ jQuery的getJSON方法就是JSONP的一個應用。 ~~~ $.getJSON( "http://example.com/api", function (data){ .... }) ~~~ $.getJSON方法的第一個參數是服務器網址,第二個參數是回調函數,該回調函數的參數就是服務器返回的JSON數據。 ## CORS CORS的全稱是“跨域資源共享”(Cross-origin resource sharing),它提出一種方法,允許JavaScript代碼向另一個域名發出XMLHttpRequests請求,從而克服了傳統上Ajax只能在同一個域名下使用的限制(same origin security policy)。 所有主流瀏覽器都支持該方法,不過IE8和IE9的該方法不是部署在XMLHttpRequest對象,而是部署在XDomainRequest對象。檢查瀏覽器是否支持的代碼如下: ~~~ var request = new XMLHttpRequest(); if("withCredentials" in request) { // 發出跨域請求 } ~~~ CORS的原理其實很簡單,就是增加一條HTTP頭信息的查詢,詢問服務器端,當前請求的域名是否在許可名單之中,以及可以使用哪些HTTP動詞。如果得到肯定的答復,就發出XMLHttpRequest請求。這種機制叫做“預檢”(preflight)。 “預檢”的專用HTTP頭信息是Origin。假定用戶正在瀏覽來自www.example.com的網頁,該網頁需要向Google請求數據,這時瀏覽器會向該域名詢問是否同意跨域請求,發出的HTTP頭信息如下: ~~~ OPTIONS /resources/post-here/ HTTP/1.1 Host: www.google.com User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Connection: keep-alive Origin: http://www.example.com Access-Control-Request-Method: POST Access-Control-Request-Headers: X-PINGOTHER ~~~ 上面的HTTP請求,它的動詞是OPTIONS,表示這是一個“預檢”請求。除了提供瀏覽器信息,里面關鍵的一行是Origin頭信息。 ~~~ Origin: http://www.example.com ~~~ 這行HTTP頭信息表示,請求來自www.example.com。服務端如果同意,就返回一個Access-Control-Allow-Origin頭信息。 預檢請求中,瀏覽器還告訴服務器,實際發出請求,將使用HTTP動詞POST,以及一個自定義的頭信息X-PINGOTHER。 ~~~ Access-Control-Request-Method: POST Access-Control-Request-Headers: X-PINGOTHER ~~~ 服務器收到預檢請求之后,做出了回應。 ~~~ HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:15:39 GMT Server: Apache/2.0.61 (Unix) Access-Control-Allow-Origin: http://www.example.com Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: X-PINGOTHER Access-Control-Max-Age: 1728000 Vary: Accept-Encoding, Origin Content-Encoding: gzip Content-Length: 0 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Content-Type: text/plain ~~~ 上面的HTTP回應里面,關鍵的是Access-Control-Allow-Origin頭信息。這表示服務器同意www.example.com的跨域請求。 ~~~ Access-Control-Allow-Origin: http://www.example.com ~~~ 如果不同意,服務器端會返回一個錯誤。 如果服務器端對所有網站都開放,可以返回一個星號(*)通配符。 ~~~ Access-Control-Allow-Origin: * ~~~ 服務器還告訴瀏覽器,允許的HTTP動詞是POST、GET、OPTIONS,也允許自定義的頭信息X-PINGOTHER, ~~~ Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: X-PINGOTHER Access-Control-Max-Age: 1728000 ~~~ 如果服務器通過了預檢請求,則以后每次瀏覽器正常的HTTP請求,都會有一個origin頭信息;服務器的回應,也都會有一個Access-Control-Allow-Origin頭信息。Access-Control-Max-Age頭信息表示,允許緩存該條回應1728000秒(即20天),在此期間,不用發出另一條預檢請求。 由于整個過程都是瀏覽器自動后臺完成,不用用戶參與,所以對于開發者來說,使用Ajax跨域請求與同域請求沒有區別,代碼完全一樣。但是,這需要服務器的支持,所以在使用CORS之前,要查看一下所請求的網站是否支持。 CORS機制默認不發送cookie和HTTP認證信息,除非在Ajax請求中打開withCredentials屬性。 ~~~ var request = new XMLHttpRequest(); request.withCredentials = true; ~~~ 同時,服務器返回HTTP頭信息時,也必須打開Access-Control-Allow-Credentials選項。否則,瀏覽器會忽略服務器返回的回應。 ~~~ Access-Control-Allow-Credentials: true ~~~ 需要注意的是,此時Access-Control-Allow-Origin不能指定為星號,必須指定明確的、與請求網頁一致的域名。同時,cookie依然遵循同源政策,只有用服務器域名(前例是www.google.com)設置的cookie才會上傳,其他域名下的cookie并不會上傳,且網頁代碼中的document.cookie也無法讀取www.google.com域名下的cookie。 CORS機制與JSONP模式的使用目的相同,而且更強大。JSONP只支持GET請求,CORS可以支持所有類型的HTTP請求。在發生錯誤的情況下,CORS可以得到更詳細的錯誤信息,部署更有針對性的錯誤處理代碼。JSONP的優勢在于可以用于老式瀏覽器,以及可以向不支持CORS的網站請求數據。 ## Fetch API ### 基本用法 Ajax操作所用的XMLHttpRequest對象,已經有十多年的歷史,它的API設計并不是很好,輸入、輸出、狀態都在同一個接口管理,容易寫出非常混亂的代碼。Fetch API是一種新規范,用來取代XMLHttpRequest對象。它主要有兩個特點,一是簡化接口,將API分散在幾個不同的對象上,二是返回Promise對象,避免了嵌套的回調函數。 檢查瀏覽器是否部署了這個API的代碼如下。 ~~~ if (fetch in window){ // 支持 } else { // 不支持 } ~~~ 下面是一個Fetch API的簡單例子。 ~~~ var URL = 'http://some/path'; fetch(URL).then(function(response) { return response.json(); }).then(function(json) { someOperator(json); }); ~~~ 上面代碼向服務器請求JSON文件,獲取后再做進一步處理。 下面比較XMLHttpRequest寫法與Fetch寫法的不同。 ~~~ function reqListener() { var data = JSON.parse(this.responseText); console.log(data); } function reqError(err) { console.log('Fetch Error :-S', err); } var oReq = new XMLHttpRequest(); oReq.onload = reqListener; oReq.onerror = reqError; oReq.open('get', './api/some.json', true); oReq.send(); ~~~ 同樣的操作用Fetch實現如下。 ~~~ fetch('./api/some.json') .then(function(response) { if (response.status !== 200) { console.log('請求失敗,狀態碼:' + response.status); return; } response.json().then(function(data) { console.log(data); }); }).catch(function(err) { console.log('出錯:', err); }); ~~~ 上面代碼中,因為HTTP請求返回的response對象是一個Stream對象,所以需要使用`response.json`方法轉為JSON格式,不過這個方法返回的是一個Promise對象。 ### fetch() fetch方法的第一個參數可以是URL字符串,也可以是后文要講到的Request對象實例。Fetch方法返回一個Promise對象,并將一個response對象傳給回調函數。 response對象還有一個ok屬性,如果返回的狀態碼在200到299之間(即請求成功),這個屬性為true,否則為false。因此,上面的代碼可以寫成下面這樣。 ~~~ fetch("./api/some.json").then(function(response) { if (response.ok) { response.json().then(function(data) { console.log(data); }); } else { console.log("請求失敗,狀態碼為", response.status); } }, function(err) { console.log("出錯:", err); }); ~~~ response對象除了json方法,還包含了HTTP回應的元數據。 ~~~ fetch('users.json').then(function(response) { console.log(response.headers.get('Content-Type')); console.log(response.headers.get('Date')); console.log(response.status); console.log(response.statusText); console.log(response.type); console.log(response.url); }); ~~~ 上面代碼中,response對象有很多屬性,其中的`response.type`屬性比較特別,表示HTTP回應的類型,它有以下三個值。 * basic:正常的同域請求 * cors:CORS機制下的跨域請求 * opaque:非CORS機制下的跨域請求,這時無法讀取返回的數據,也無法判斷是否請求成功 如果需要在CORS機制下發出跨域請求,需要指明狀態。 ~~~ fetch('http://some-site.com/cors-enabled/some.json', {mode: 'cors'}) .then(function(response) { return response.text(); }) .then(function(text) { console.log('Request successful', text); }) .catch(function(error) { log('Request failed', error) }); ~~~ 除了指定模式,fetch方法的第二個參數還可以用來配置其他值,比如指定cookie連同HTTP請求一起發出。 ~~~ fetch(url, { credentials: 'include' }) ~~~ 發出POST請求的寫法如下。 ~~~ fetch("http://www.example.org/submit.php", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: "firstName=Nikhil&favColor=blue&password=easytoguess" }).then(function(res) { if (res.ok) { console.log("Perfect! Your settings are saved."); } else if (res.status == 401) { console.log("Oops! You are not authorized."); } }, function(e) { console.log("Error submitting form!"); }); ~~~ 目前,還有一些XMLHttpRequest對象可以做到,但是Fetch API還沒做到的地方,比如中途中斷HTTP請求,以及獲取HTTP請求的進度。這些不足與Fetch返回的是Promise對象有關。 ### Headers Fetch API引入三個新的對象(也是構造函數):Headers, Request 和 Response。其中,Headers對象用來構造/讀取HTTP數據包的頭信息。 ~~~ var content = "Hello World"; var reqHeaders = new Headers(); reqHeaders.append("Content-Type", "text/plain"); reqHeaders.append("Content-Length", content.length.toString()); reqHeaders.append("X-Custom-Header", "ProcessThisImmediately"); ~~~ Headers對象的實例,除了使用append方法添加屬性,也可以直接通過構造函數一次性生成。 ~~~ reqHeaders = new Headers({ "Content-Type": "text/plain", "Content-Length": content.length.toString(), "X-Custom-Header": "ProcessThisImmediately", }); ~~~ Headers對象實例還提供了一些工具方法。 ~~~ reqHeaders.has("Content-Type") // true reqHeaders.has("Set-Cookie") // false reqHeaders.set("Content-Type", "text/html") reqHeaders.append("X-Custom-Header", "AnotherValue") reqHeaders.get("Content-Length") // 11 reqHeaders.getAll("X-Custom-Header") // ["ProcessThisImmediately", "AnotherValue"] reqHeaders.delete("X-Custom-Header") reqHeaders.getAll("X-Custom-Header") // [] ~~~ 生成Header實例以后,可以將它作為第二個參數,傳入Request方法。 ~~~ var headers = new Headers(); headers.append('Accept', 'application/json'); var request = new Request(URL, {headers: headers}); fetch(request).then(function(response) { console.log(response.headers); }); ~~~ 同樣地,Headers實例可以用來構造Response方法。 ~~~ var headers = new Headers({ 'Content-Type': 'application/json', 'Cache-Control': 'max-age=3600' }); var response = new Response( JSON.stringify({photos: {photo: []}}), {'status': 200, headers: headers} ); response.json().then(function(json) { insertPhotos(json); }); ~~~ 上面代碼中,構造了一個HTTP回應。目前,瀏覽器構造HTTP回應沒有太大用處,但是隨著Service Worker的部署,不久瀏覽器就可以向Service Worker發出HTTP回應。 ### Request對象 Request對象用來構造HTTP請求。 ~~~ var req = new Request("/index.html"); req.method // "GET" req.url // "http://example.com/index.html" ~~~ Request對象的第二個參數,表示配置對象。 ~~~ var uploadReq = new Request("/uploadImage", { method: "POST", headers: { "Content-Type": "image/png", }, body: "image data" }); ~~~ 上面代碼指定Request對象使用POST方法發出,并指定HTTP頭信息和信息體。 下面是另一個例子。 ~~~ var req = new Request(URL, {method: 'GET', cache: 'reload'}); fetch(req).then(function(response) { return response.json(); }).then(function(json) { someOperator(json); }); ~~~ 上面代碼中,指定請求方法為GET,并且要求瀏覽器不得緩存response。 Request對象實例有兩個屬性是只讀的,不能手動設置。一個是referrer屬性,表示請求的來源,由瀏覽器設置,有可能是空字符串。另一個是context屬性,表示請求發出的上下文,如果是image,表示是從img標簽發出,如果是worker,表示是從worker腳本發出,如果是fetch,表示是從fetch函數發出的。 Request對象實例的mode屬性,用來設置是否跨域,合法的值有以下三種:same-origin、no-cors(默認值)、cors。當設置為same-origin時,只能向同域的URL發出請求,否則會報錯。 ~~~ var arbitraryUrl = document.getElementById("url-input").value; fetch(arbitraryUrl, { mode: "same-origin" }).then(function(res) { console.log("Response succeeded?", res.ok); }, function(e) { console.log("Please enter a same-origin URL!"); }); ~~~ 上面代碼中,如果用戶輸入的URL不是同域的,將會報錯,否則就會發出請求。 如果mode屬性為no-cors,就與默認的瀏覽器行為沒有不同,類似script標簽加載外部腳本文件、img標簽加載外部圖片。如果mode屬性為cors,就可以向部署了CORS機制的服務器,發出跨域請求。 ~~~ var u = new URLSearchParams(); u.append('method', 'flickr.interestingness.getList'); u.append('api_key', '<insert api key here>'); u.append('format', 'json'); u.append('nojsoncallback', '1'); var apiCall = fetch('https://api.flickr.com/services/rest?' + u); apiCall.then(function(response) { return response.json().then(function(json) { // photo is a list of photos. return json.photos.photo; }); }).then(function(photos) { photos.forEach(function(photo) { console.log(photo.title); }); }); ~~~ 上面代碼是向Flickr API發出圖片請求的例子。 Request對象的一個很有用的功能,是在其他Request實例的基礎上,生成新的Request實例。 ~~~ var postReq = new Request(req, {method: 'POST'}); ~~~ ### Response fetch方法返回Response對象實例,它有以下屬性。 * status:整數值,表示狀態碼(比如200) * statusText:字符串,表示狀態信息,默認是“OK” * ok:布爾值,表示狀態碼是否在200-299的范圍內 * headers:Headers對象,表示HTTP回應的頭信息 * url:字符串,表示HTTP請求的網址 * type:字符串,合法的值有五個basic、cors、default、error、opaque。basic表示正常的同域請求;cors表示CORS機制的跨域請求;error表示網絡出錯,無法取得信息,status屬性為0,headers屬性為空,并且導致fetch函數返回Promise對象被拒絕;opaque表示非CORS機制的跨域請求,受到嚴格限制。 Response對象還有兩個靜態方法。 * Response.error() 返回一個type屬性為error的Response對象實例 * Response.redirect(url, status) 返回的Response對象實例會重定向到另一個URL ### body屬性 Request對象和Response對象都有body屬性,表示請求的內容。body屬性可能是以下的數據類型。 * ArrayBuffer * ArrayBufferView (Uint8Array等) * Blob/File * string * URLSearchParams * FormData ~~~ var form = new FormData(document.getElementById('login-form')); fetch("/login", { method: "POST", body: form }) ~~~ 上面代碼中,Request對象的body屬性為表單數據。 Request對象和Response對象都提供以下方法,用來讀取body。 * arrayBuffer() * blob() * json() * text() * formData() 注意,上面這些方法都只能使用一次,第二次使用就會報錯,也就是說,body屬性只能讀取一次。Request對象和Response對象都有bodyUsed屬性,返回一個布爾值,表示body是否被讀取過。 ~~~ var res = new Response("one time use"); console.log(res.bodyUsed); // false res.text().then(function(v) { console.log(res.bodyUsed); // true }); console.log(res.bodyUsed); // true res.text().catch(function(e) { console.log("Tried to read already consumed Response"); }); ~~~ 上面代碼中,第二次通過text方法讀取Response對象實例的body時,就會報錯。 這是因為body屬性是一個stream對象,數據只能單向傳送一次。這樣的設計是為了允許JavaScript處理視頻、音頻這樣的大型文件。 如果希望多次使用body屬性,可以使用Response對象和Request對象的clone方法。它必須在body還沒有讀取前調用,返回一個前的body,也就是說,需要使用幾次body,就要調用幾次clone方法。 ~~~ addEventListener('fetch', function(evt) { var sheep = new Response("Dolly"); console.log(sheep.bodyUsed); // false var clone = sheep.clone(); console.log(clone.bodyUsed); // false clone.text(); console.log(sheep.bodyUsed); // false console.log(clone.bodyUsed); // true evt.respondWith(cache.add(sheep.clone()).then(function(e) { return sheep; }); }); ~~~ ## 參考鏈接 * MDN,?[Using XMLHttpRequest](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest) * Mathias Bynens,?[Loading JSON-formatted data with Ajax and xhr.responseType='json'](http://mathiasbynens.be/notes/xhr-responsetype-json) * Eric Bidelman,?[New Tricks in XMLHttpRequest2](http://www.html5rocks.com/en/tutorials/file/xhr2/) * Matt West,?[Uploading Files with AJAX](http://blog.teamtreehouse.com/uploading-files-ajax) * Monsur Hossain,?[Using CORS](http://www.html5rocks.com/en/tutorials/cors/) * MDN,?[HTTP access control (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS) * Matt Gaunt,?[Introduction to fetch()](http://updates.html5rocks.com/2015/03/introduction-to-fetch) * Nikhil Marathe,?[This API is so Fetching!](https://hacks.mozilla.org/2015/03/this-api-is-so-fetching/) * Ludovico Fischer,?[Introduction to the Fetch API](http://www.sitepoint.com/introduction-to-the-fetch-api/)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看