From 218934fa2ed1c702a6d3923d2aa2cc6b43c48684 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:43:23 -0500 Subject: initial commit --- files/zh-tw/web/api/xmlhttprequest/index.html | 177 +++++ .../xmlhttprequest/onreadystatechange/index.html | 113 +++ .../web/api/xmlhttprequest/readystate/index.html | 148 ++++ .../api/xmlhttprequest/setrequestheader/index.html | 66 ++ .../zh-tw/web/api/xmlhttprequest/status/index.html | 115 ++++ .../index.html | 260 +++++++ .../xmlhttprequest/using_xmlhttprequest/index.html | 766 +++++++++++++++++++++ .../api/xmlhttprequest/withcredentials/index.html | 48 ++ .../api/xmlhttprequest/xmlhttprequest/index.html | 50 ++ 9 files changed, 1743 insertions(+) create mode 100644 files/zh-tw/web/api/xmlhttprequest/index.html create mode 100644 files/zh-tw/web/api/xmlhttprequest/onreadystatechange/index.html create mode 100644 files/zh-tw/web/api/xmlhttprequest/readystate/index.html create mode 100644 files/zh-tw/web/api/xmlhttprequest/setrequestheader/index.html create mode 100644 files/zh-tw/web/api/xmlhttprequest/status/index.html create mode 100644 files/zh-tw/web/api/xmlhttprequest/synchronous_and_asynchronous_requests/index.html create mode 100644 files/zh-tw/web/api/xmlhttprequest/using_xmlhttprequest/index.html create mode 100644 files/zh-tw/web/api/xmlhttprequest/withcredentials/index.html create mode 100644 files/zh-tw/web/api/xmlhttprequest/xmlhttprequest/index.html (limited to 'files/zh-tw/web/api/xmlhttprequest') diff --git a/files/zh-tw/web/api/xmlhttprequest/index.html b/files/zh-tw/web/api/xmlhttprequest/index.html new file mode 100644 index 0000000000..3258579e62 --- /dev/null +++ b/files/zh-tw/web/api/xmlhttprequest/index.html @@ -0,0 +1,177 @@ +--- +title: XMLHttpRequest +slug: Web/API/XMLHttpRequest +tags: + - AJAX + - Fixit + - HTTP + - MakeBrowserAgnostic + - NeedsCleanup + - NeedsMobileBrowserCompatibility + - NeedsTranslation + - TopicStub + - XMLHttpRequest +translation_of: Web/API/XMLHttpRequest +--- +
{{DefaultAPISidebar("XMLHttpRequest")}}
+ +

藉由 XMLHttpRequest(XHR)物件的方式來存取伺服器端的資料,可以讓你直接經由指定的 URL 擷取資料卻不用刷新整個網頁。這樣一來當想要更新網頁中的部分資料時,不再需要藉由刷新整個頁面的方法而中斷使用者的操作。在{{Glossary("AJAX")}}應用中 XMLHttpRequest 被大量的使用。

+ +

{{InheritanceDiagram(650, 150)}}

+ +

雖然 XMLHttpRequest 這個物件的命名包含了 XML 與 HTTP 等字眼,但實際上 XMLHttpRequest 可用來接收任何類型的資料,不限於 XML 類型而已。

+ +

如果在資料交換的時候,需要接收從伺服器端傳來的事件或訊息:可以考慮透過{{domxref("EventSource")}}介面使用server-sent 事件。對於和伺服器全雙工的資訊交換,WebSockets 可能是較佳的選擇。

+ +

建構式

+ +
+
{{domxref("XMLHttpRequest.XMLHttpRequest", "XMLHttpRequest()")}}
+
建構式用來初始化一個 XMLHttpRequest 物件。必須在其他任何所屬方法被呼叫之前被呼叫。
+
+ +

屬性

+ +

此介面也繼承了 {{domxref("XMLHttpRequestEventTarget")}} 及 {{domxref("EventTarget")}} 的屬性。

+ +
+
{{domxref("XMLHttpRequest.onreadystatechange")}}
+
一個 {{domxref("EventHandler")}}(事件處理器)函式,會於 readyState 屬性之狀態改變時被呼叫。
+
{{domxref("XMLHttpRequest.readyState")}} {{readonlyinline}}
+
回傳一個無符號短整數(unsigned short)代表請求之狀態。
+
{{domxref("XMLHttpRequest.response")}} {{readonlyinline}}
+
回傳的內容可能是 {{domxref("ArrayBuffer")}}、{{domxref("Blob")}}、{{domxref("Document")}}、JavaScript 物件或 {{domxref("DOMString")}}。完全根據 {{domxref("XMLHttpRequest.responseType")}} 的值決定回傳的內容為何種型態,資料為回應實體中的內容(response entity body)。
+
{{domxref("XMLHttpRequest.responseText")}} {{readonlyinline}}
+
回傳一個 {{domxref("DOMString")}},其內容為請求之回應的文字內容。如請求失敗或尚未發送,則為 null
+
{{domxref("XMLHttpRequest.responseType")}}
+
為一可列舉(enumerated)值,定義回應內容的資料類型(response type)。
+
{{domxref("XMLHttpRequest.responseURL")}} {{readonlyinline}}
+
回傳一個回應(response)的序列化 URL,如 URL 為 null 則回傳空字串。
+
{{domxref("XMLHttpRequest.responseXML")}} {{readonlyinline}}
+
回傳一個 {{domxref("Document")}},其內容為請求之回應內容所解析成的文件物件。如請求失敗或尚未發送,又或是無法解析成 XML、HTML,則為 null。Not available in workers.
+
{{domxref("XMLHttpRequest.status")}} {{readonlyinline}}
+
回傳一個無符號短整數(unsigned short)表示已發送請求之回應的狀態。
+
{{domxref("XMLHttpRequest.statusText")}} {{readonlyinline}}
+
回傳一個 {{domxref("DOMString")}} 表示 HTTP 伺服器回應之字串。和 {{domxref("XMLHTTPRequest.status")}} 不同的是,XMLHttpRequest.statusText 包含了回應的整個文字訊息(如 "200 OK")。
+
+ +
+

Note: The HTTP/2 specification (8.1.2.4 Response Pseudo-Header Fields), HTTP/2 does not define a way to carry the version or reason phrase that is included in an HTTP/1.1 status line.

+
+ +
+
{{domxref("XMLHttpRequest.timeout")}}
+
為一無符號長整數(unsigned long),代表一個請求在逾時而被自動中止前的可等待時間(毫秒)。
+
{{domxref("XMLHttpRequestEventTarget.ontimeout")}}
+
為一 {{domxref("EventHandler")}} 物件,會於請求逾時時被呼叫。{{gecko_minversion_inline("12.0")}}
+
{{domxref("XMLHttpRequest.upload")}} {{readonlyinline}}
+
為一 {{domxref("XMLHttpRequestUpload")}} 物件,代表上傳的進度。
+
{{domxref("XMLHttpRequest.withCredentials")}}
+
{{domxref("Boolean","布林值")}}。表示是否允許在跨站存取(cross-site Access-Control)之請求當中,發送如 cookies 或 authorization headers 等憑證資訊(credentials)。
+
+ +

非標準屬性

+ +
+
{{domxref("XMLHttpRequest.channel")}}{{ReadOnlyInline}}
+
是一個 {{Interface("nsIChannel")}}。當執行要求時,物件使用的頻道(Channel)。
+
{{domxref("XMLHttpRequest.mozAnon")}}{{ReadOnlyInline}}
+
為一個布林值。如果為真,請求就會以沒有cookie及authentication headers的方式送出。
+
{{domxref("XMLHttpRequest.mozSystem")}}{{ReadOnlyInline}}
+
這是一個布林值。If true, the same origin policy will not be enforced on the request.
+
{{domxref("XMLHttpRequest.mozBackgroundRequest")}}
+
這是一個布林值。指出該物件是否為一個背景型態的服務要求。
+
{{domxref("XMLHttpRequest.mozResponseArrayBuffer")}}{{gecko_minversion_inline("2.0")}} {{obsolete_inline("6")}} {{ReadOnlyInline}}
+
Is an ArrayBuffer. The response to the request, as a JavaScript typed array.
+
{{domxref("XMLHttpRequest.multipart")}}{{obsolete_inline("22")}}
+
This Gecko-only feature, a boolean, was removed in Firefox/Gecko 22. Please use Server-Sent Events, Web Sockets, or responseText from progress events instead.
+
+ +

事件處理器

+ +

所有瀏覽器都支援 XMLHttpRequest 物件實體的 onreadystatechange 屬性。

+ +

之後,各個瀏覽器實作了多種額外的事件處理器(如 onloadonerroronprogress 等)。請參考使用 XMLHttpRequest

+ +

除了以 on* 屬性來設定事件處理函式,更多現代覽瀏器(包括 Firefox)也支援使用標準的 addEventListener() API 註冊監聽 XMLHttpRequest 的事件。

+ +
+
+ +

方法

+ +
+
{{domxref("XMLHttpRequest.abort()")}}
+
中止已發出的請求。
+
{{domxref("XMLHttpRequest.getAllResponseHeaders()")}}
+
回傳所有的回應標頭(response headers),為一以斷行字元(CRLF)分行的字串,如未接收到回應則為 null
+
{{domxref("XMLHttpRequest.getResponseHeader()")}}
+
回傳指定標頭文字之字串,假如回應尚未被接收或是標頭不存在於回應中則為 null
+
{{domxref("XMLHttpRequest.open()")}}
+
初始化一個請求。此方法用於 JavaScript 中;若要在 native code 中初始化請求,請以 openRequest() 作為替代。
+
{{domxref("XMLHttpRequest.overrideMimeType()")}}
+
覆寫伺服器回傳的 MIME type。
+
{{domxref("XMLHttpRequest.send()")}}
+
發送請求。如果為非同步請求(預設值),此方法將在發出請求後便立即回傳(return)。
+
{{domxref("XMLHttpRequest.setRequestHeader()")}}
+
設定 HTTP 請求標頭(request header)值。setRequestHeader() 可被呼叫的時間點必須於 open() 之後、在 send() 之前。
+
+ +

非標準方法

+ +
+
{{domxref("XMLHttpRequest.init()")}}
+
使用 C++ 程式時,用來初始化這個物件。
+
+ +
注意: 請勿在 JavaScript 中呼叫這個方法。
+ +
+
{{domxref("XMLHttpRequest.openRequest()")}}
+
初始化請求。這方法是用於原生程式,若想在 JavaScript 中初始化一個請求,請使用 open() 這個方法來代替。請參照 open() 的相關文件。
+
{{domxref("XMLHttpRequest.sendAsBinary()")}}{{deprecated_inline()}}
+
另一種 send() 方法,用來送出二進位資料。
+
+ +

規範

+ + + + + + + + + + + + + + +
規範狀態註解
{{SpecName('XMLHttpRequest')}}{{Spec2('XMLHttpRequest')}}Live standard, latest version
+ +

瀏覽器相容性

+ + + +
{{Compat("api.XMLHttpRequest")}}
+ +

參見

+ + diff --git a/files/zh-tw/web/api/xmlhttprequest/onreadystatechange/index.html b/files/zh-tw/web/api/xmlhttprequest/onreadystatechange/index.html new file mode 100644 index 0000000000..817daf0efa --- /dev/null +++ b/files/zh-tw/web/api/xmlhttprequest/onreadystatechange/index.html @@ -0,0 +1,113 @@ +--- +title: XMLHttpRequest.onreadystatechange +slug: Web/API/XMLHttpRequest/onreadystatechange +translation_of: Web/API/XMLHttpRequest/onreadystatechange +--- +
{{APIRef}}
+ +

An EventHandler that is called whenever the readyState attribute changes. The callback is called from the user interface thread. The XMLHttpRequest.onreadystatechange property contains the event handler to be called when the {{event("readystatechange")}} event is fired, that is every time the {{domxref("XMLHttpRequest.readyState", "readyState")}} property of the {{domxref("XMLHttpRequest")}} changes.

+ +
+

Warning: This should not be used with synchronous requests and must not be used from native code.

+
+ +

The readystatechange event will not be fired when an XMLHttpRequest request is cancelled with the abort() method.

+ +
+

UPDATE: it's firing in the latest version of browsers (Firefox 51.0.1, Opera 43.0.2442.991, Safari 10.0.3 (12602.4.8), Chrome 54.0.2840.71, Edge, IE11). Example here - just reaload page few times.

+
+ +

語法

+ +
XMLHttpRequest.onreadystatechange = callback;
+ +

+ + + +

範例

+ +
var xhr = new XMLHttpRequest(),
+    method = "GET",
+    url = "https://developer.mozilla.org/";
+
+xhr.open(method, url, true);
+xhr.onreadystatechange = function () {
+        if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
+            console.log(xhr.responseText);
+        }
+    };
+xhr.send();
+ +

規範

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('XMLHttpRequest', '#handler-xhr-onreadystatechange')}}{{Spec2('XMLHttpRequest')}}WHATWG living standard
+ +

瀏覽器相容性

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{CompatChrome(1)}}{{CompatGeckoDesktop(1.0)}}{{CompatIe(7)}}[1]{{CompatVersionUnknown}}{{CompatSafari(1.2)}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}1.0{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

[1] Internet Explorer version 5 and 6 supported ajax calls using ActiveXObject().

diff --git a/files/zh-tw/web/api/xmlhttprequest/readystate/index.html b/files/zh-tw/web/api/xmlhttprequest/readystate/index.html new file mode 100644 index 0000000000..3f7e909fe0 --- /dev/null +++ b/files/zh-tw/web/api/xmlhttprequest/readystate/index.html @@ -0,0 +1,148 @@ +--- +title: XMLHttpRequest.readyState +slug: Web/API/XMLHttpRequest/readyState +translation_of: Web/API/XMLHttpRequest/readyState +--- +

{{APIRef('XMLHttpRequest')}}

+ +

XMLHttpRequest.readyState 屬性會回傳一個 XMLHttpRequest 客戶端物件目前的狀態。一個 XHR 客戶端可以為下列其中一種狀態:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
狀態說明
0UNSENT客戶端已被建立,但 open() 方法尚未被呼叫。
1OPENEDopen() 方法已被呼叫。
2HEADERS_RECEIVEDsend() 方法已被呼叫,而且可取得 header 與狀態。
3LOADING回應資料下載中,此時 responseText 會擁有部分資料。
4DONE完成下載操作。
+ +
+
UNSENT
+
XMLHttpRequest 客戶端物件已被建立,但 open() 方法尚未被呼叫。
+
OPENED
+
open() 方法已被呼叫。於此狀態時,可以使用 setRequestHeader() 方法設定請求標頭(request headers),並可呼叫 send() 方法來發送請求。
+
HEADERS_RECEIVED
+
send() 方法已被呼叫,並且已接收到回應標頭(response header)。
+
LOADING
+
正在接收回應內容(response's body)。如 responseType 屬性為 "text" 或空字串,則 responseText 屬性將會在載入的過程中擁有已載入部分之回應(response)內容中的文字。
+
DONE
+
請求操作已完成。這意味著資料傳輸可能已成功完成或是已失敗。
+
+ +
+

這些狀態名稱在 Internet Explorer 中略有不同。其中 UNSENT, OPENED, HEADERS_RECEIVED, LOADING 和 DONE 變成了 READYSTATE_UNINITIALIZED (0), READYSTATE_LOADING (1), READYSTATE_LOADED (2), READYSTATE_INTERACTIVE (3) 和READYSTATE_COMPLETE (4)。

+
+ +

範例

+ +
var xhr = new XMLHttpRequest();
+console.log('UNSENT', xhr.readyState); // readyState will be 0
+
+xhr.open('GET', '/api', true);
+console.log('OPENED', xhr.readyState); // readyState will be 1
+
+xhr.onprogress = function () {
+    console.log('LOADING', xhr.readyState); // readyState will be 3
+};
+
+xhr.onload = function () {
+    console.log('DONE', xhr.readyState); // readyState will be 4
+};
+
+xhr.send(null);
+
+ +

規範

+ + + + + + + + + + + + + + +
規範狀態註解
{{SpecName('XMLHttpRequest', '#states')}}{{Spec2('XMLHttpRequest')}}WHATWG living standard
+ +

瀏覽器相容性

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + +
功能ChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
基本支援{{CompatChrome(1)}}{{CompatGeckoDesktop("1.0")}}[1]{{CompatIe(7)}}{{CompatVersionUnknown}}{{CompatSafari("1.2")}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
功能AndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
基本支援{{CompatUnknown}}1.0{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
diff --git a/files/zh-tw/web/api/xmlhttprequest/setrequestheader/index.html b/files/zh-tw/web/api/xmlhttprequest/setrequestheader/index.html new file mode 100644 index 0000000000..a8219e7240 --- /dev/null +++ b/files/zh-tw/web/api/xmlhttprequest/setrequestheader/index.html @@ -0,0 +1,66 @@ +--- +title: XMLHttpRequest.setRequestHeader() +slug: Web/API/XMLHttpRequest/setRequestHeader +translation_of: Web/API/XMLHttpRequest/setRequestHeader +--- +
{{APIRef('XMLHttpRequest')}}
+ +

{{domxref("XMLHttpRequest")}} 物件中的 setRequestHeader() 方法用來設定 HTTP 的表頭請求。當使用 setRequestHeader() 的時候,必須在 {{domxref("XMLHttpRequest.open", "open()")}} 之後呼叫,同時也必須在 {{domxref("XMLHttpRequest.send", "send()")}} 之前呼叫。如果這個方法被呼叫了許多次,且設定的表頭是一樣的,那所有設定的值會被合併成一個單一的表頭請求。

+ +

在第一次呼叫 setRequestHeader() 之後的每一次的呼叫,都會把給定的文字附加在已存在的表頭內容之後。

+ +

If no {{HTTPHeader("Accept")}} header has been set using this, an Accept header with the type "*/*" is sent with the request when {{domxref("XMLHttpRequest.send", "send()")}} is called.

+ +

基於安全的理由,有些表頭只有使用者代理器可以使用。這些表頭包含了: {{Glossary("Forbidden_header_name", "forbidden header names", 1)}}  和 {{Glossary("Forbidden_response_header_name", "forbidden response header names", 1)}}.

+ +
+

Note: For your custom fields, you may encounter a "not allowed by Access-Control-Allow-Headers in preflight response" exception when you send requests across domains. In this situation, you need to set up the {{HTTPHeader("Access-Control-Allow-Headers")}} in your response header at server side.

+
+ +

語法

+ +
XMLHttpRequest.setRequestHeader(header, value)
+
+ +

參數

+ +
+
header
+
想要設定所屬值的表頭名稱。
+
value
+
用來設定表頭本身的值。
+
+ +

回傳值

+ +

未定義

+ +

規範

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('XMLHttpRequest', '#the-setrequestheader()-method', 'setRequestHeader()')}}{{Spec2('XMLHttpRequest')}}WHATWG living standard
+ +

瀏覽器相容性

+ + + +

{{Compat("api.XMLHttpRequest.setRequestHeader")}}

+ +

參見

+ + diff --git a/files/zh-tw/web/api/xmlhttprequest/status/index.html b/files/zh-tw/web/api/xmlhttprequest/status/index.html new file mode 100644 index 0000000000..c54ece9939 --- /dev/null +++ b/files/zh-tw/web/api/xmlhttprequest/status/index.html @@ -0,0 +1,115 @@ +--- +title: XMLHttpRequest.status +slug: Web/API/XMLHttpRequest/status +translation_of: Web/API/XMLHttpRequest/status +--- +
{{APIRef('XMLHttpRequest')}}
+ +

XMLHttpRequest.status 屬性根據XMLHttpRequest的回應傳回數值化的狀況編碼。狀況編碼為一正短整數(unsigned short)。Before the request is complete, the value of status will be 0. It is worth noting that browsers report a status of 0 in case of XMLHttpRequest errors too.

+ +

The status codes returned are the standard HTTP status codes. For example, status 200 denotes a successful request. If the server response doesn't explicitly specify a status code, XMLHttpRequest.status will assume the default value of 200.

+ +

Example

+ +
var xhr = new XMLHttpRequest();
+console.log('UNSENT', xhr.status);
+
+xhr.open('GET', '/server', true);
+console.log('OPENED', xhr.status);
+
+xhr.onprogress = function () {
+  console.log('LOADING', xhr.status);
+};
+
+xhr.onload = function () {
+  console.log('DONE', xhr.status);
+};
+
+xhr.send(null);
+
+/**
+ * Outputs the following:
+ *
+ * UNSENT 0
+ * OPENED 0
+ * LOADING 200
+ * DONE 200
+ */
+
+ +

Specifications

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('XMLHttpRequest', '#the-status-attribute')}}{{Spec2('XMLHttpRequest')}}WHATWG living standard
+ +

Browser compatibility

+ +
{{CompatibilityTable}}
+ +
+ + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari (WebKit)
Basic support{{CompatChrome(1)}}{{CompatGeckoDesktop("1.0")}}[1]{{CompatIe(7)}}[1]{{CompatVersionUnknown}}{{CompatSafari("1.2")}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatUnknown}}1.0{{CompatVersionUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

[1] Internet Explorer versions 5 and 6 lacked the XMLHttpRequest object, but provided a way to make AJAX requests using ActiveXObject.

+ +

See also

+ + diff --git a/files/zh-tw/web/api/xmlhttprequest/synchronous_and_asynchronous_requests/index.html b/files/zh-tw/web/api/xmlhttprequest/synchronous_and_asynchronous_requests/index.html new file mode 100644 index 0000000000..e8a148b5a9 --- /dev/null +++ b/files/zh-tw/web/api/xmlhttprequest/synchronous_and_asynchronous_requests/index.html @@ -0,0 +1,260 @@ +--- +title: Synchronous and asynchronous requests +slug: Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests +translation_of: Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests +--- +

XMLHttpRequest 支持同步和非同步請求,一般來說,建議使用非同步請求。

+ +

In short, synchronous requests block the execution of code which creates "freezing" on the screen and an unresponsive user experience. 

+ +

非同步請求

+ +

If you use XMLHttpRequest from an extension, you should use it asynchronously.  In this case, you receive a callback when the data has been received, which lets the browser continue to work as normal while your request is being handled.

+ +

範例: send a file to the console log

+ +

這是使用非同步XMLHttpRequest的基本方式

+ +
var xhr = new XMLHttpRequest();
+xhr.open("GET", "/bar/foo.txt", true);
+xhr.onload = function (e) {
+  if (xhr.readyState === 4) {
+    if (xhr.status === 200) {
+      console.log(xhr.responseText);
+    } else {
+      console.error(xhr.statusText);
+    }
+  }
+};
+xhr.onerror = function (e) {
+  console.error(xhr.statusText);
+};
+xhr.send(null); 
+ +

Line 2第3個參數為布林值,true表示非同步請求。

+ +

Line 3 creates an event handler function object and assigns it to the request's onload attribute.  This handler looks at the request's readyState to see if the transaction is complete in line 4, and if it is, and the HTTP status is 200, dumps the received content.  If an error occurred, an error message is displayed.

+ +

Line 15 actually initiates the request.  The callback routine is called whenever the state of the request changes.

+ +

Example: creating a standard function to read external files

+ +

In some cases you must read many external files. This is a standard function which uses the XMLHttpRequest object asynchronously in order to switch the content of the read file to a specified listener.

+ +
function xhrSuccess () { this.callback.apply(this, this.arguments); }
+
+function xhrError () { console.error(this.statusText); }
+
+function loadFile (sURL, fCallback /*, argumentToPass1, argumentToPass2, etc. */) {
+  var oReq = new XMLHttpRequest();
+  oReq.callback = fCallback;
+  oReq.arguments = Array.prototype.slice.call(arguments, 2);
+  oReq.onload = xhrSuccess;
+  oReq.onerror = xhrError;
+  oReq.open("get", sURL, true);
+  oReq.send(null);
+}
+
+ +

Usage:

+ +
function showMessage (sMsg) {
+  alert(sMsg + this.responseText);
+}
+
+loadFile("message.txt", showMessage, "New message!\n\n");
+
+ +

Line 1 declares a function which will pass all arguments after the third to the callback function when the file has been loaded.

+ +

Line 4 creates an event handler function object and assigns it to the request's onload attribute.  This handler looks at the request's readyState to see if the transaction is complete in line 5, and if it is, and the HTTP status is 200, calls the callback function.  If an error occurred, an error message is displayed.

+ +

Line 13 specifies true for its third parameter to indicate that the request should be handled asynchronously.

+ +

Line 14 actually initiates the request.

+ +

Example: using a timeout

+ +

You can use a timeout to prevent hanging your code forever while waiting for a read to occur. This is done by setting the value of the timeout property on the XMLHttpRequest object, as shown in the code below:

+ +
  var args = arguments.slice(2);
+  var xhr = new XMLHttpRequest();
+  xhr.ontimeout = function () {
+    console.error("The request for " + url + " timed out.");
+  };
+  xhr.onload = function() {
+    if (xhr.readyState === 4) {
+      if (xhr.status === 200) {
+        callback.apply(xhr, args);
+      } else {
+        console.error(xhr.statusText);
+      }
+    }
+  };
+  xhr.open("GET", url, true);
+  xhr.timeout = timeout;
+  xhr.send(null);
+}
+
+ +

Notice the addition of code to handle the "timeout" event by setting the ontimeout handler.

+ +

Usage:

+ +
function showMessage (sMsg) {
+  alert(sMsg + this.responseText);
+}
+
+loadFile("message.txt", 2000, showMessage, "New message!\n");
+
+ +

Here, we're specifying a timeout of 2000 ms.

+ +
+

Note: Support for timeout was added in {{Gecko("12.0")}}.

+
+ +

Synchronous request

+ +
Note: Starting with Gecko 30.0 {{ geckoRelease("30.0") }}, synchronous requests on the main thread have been deprecated due to the negative effects to the user experience.
+ +

In rare cases, the use of a synchronous method is preferable to an asynchronous one.

+ +

Example: HTTP synchronous request

+ +

This example demonstrates how to make a simple synchronous request.

+ +
var request = new XMLHttpRequest();
+request.open('GET', '/bar/foo.txt', false);  // `false` makes the request synchronous
+request.send(null);
+
+if (request.status === 200) {
+  console.log(request.responseText);
+}
+
+ +

Line 3 sends the request.  The null parameter indicates that no body content is needed for the GET request.

+ +

Line 5 checks the status code after the transaction is completed.  If the result is 200 -- HTTP's "OK" result -- the document's text content is output to the console.

+ +

Example: Synchronous HTTP request from a Worker

+ +

One of the few cases in which a synchronous request does not usually block execution is the use of XMLHttpRequest within a Worker.

+ +

example.html (the main page):

+ +
<!doctype html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title>MDN Example</title>
+<script type="text/javascript">
+  var worker = new Worker("myTask.js");
+  worker.onmessage = function(event) {
+    alert("Worker said: " + event.data);
+  };
+
+  worker.postMessage("Hello");
+</script>
+</head>
+<body></body>
+</html>
+
+ +

myFile.txt (the target of the synchronous XMLHttpRequest invocation):

+ +
Hello World!!
+
+ +

myTask.js (the Worker):

+ +
self.onmessage = function (event) {
+  if (event.data === "Hello") {
+    var xhr = new XMLHttpRequest();
+    xhr.open("GET", "myFile.txt", false);  // synchronous request
+    xhr.send(null);
+    self.postMessage(xhr.responseText);
+  }
+};
+
+ +
Note: The effect, because of the use of the Worker, is however asynchronous.
+ +

It could be useful in order to interact in background with the server or to preload some content. See Using web workers for examples and details.

+ +

Irreplaceability of the synchronous use

+ +

There are some few cases in which the synchronous usage of XMLHttpRequest is not replaceable. This happens for example during the window.onunload and window.onbeforeunload events (see also below).

+ +

Sending the usual XMLHttpRequest when the page unloaded poses a problem with the asynchronous response from the server: by the time the response comes back, the page has unloaded and the callback function won’t exist anymore. This generates a JavaScript “function is not defined” error.

+ +

+ +

A possible solution is to make sure that any AJAX requests that you make on unload are make synchronously instead of asynchronously. This will ensure that the page doesn’t finish unloading before the server response comes back.

+ +

Example #1: Automatic logout before exit

+ +
window.onbeforeunload = function () {
+  var xhr = new XMLHttpRequest();
+  xhr.open("GET", "logout.php?nick=" + escape(myName), false);  // synchronous request
+  xhr.send(null);
+  if (xhr.responseText.trim() !== "logout done"); {  // "logout done" is the expected response text
+    return "Logout has failed. Do you want to complete it manually?";
+  }
+};
+
+ + + +
<!doctype html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title>MDN Example</title>
+<script type="text/javascript">
+(function () {
+
+  function dontPanic () {
+    bForsake = false;
+    return true;
+  }
+
+  onload = function () {
+    for (
+      var aLinks = document.links, nLen = aLinks.length, nIdx = 0;
+      nIdx < nLen;
+      aLinks[nIdx++].onclick = dontPanic
+    );
+  };
+
+  onbeforeunload = function () {
+    if (bForsake) {
+      /* silent synchronous request */
+      var oReq = new XMLHttpRequest();
+      oReq.open("GET", "exit.php?leave=" + escape(location.href), false);
+      oReq.send(null);
+    }
+  };
+
+  var bForsake = true;
+
+})();
+</script>
+</head>
+
+<body>
+
+<p><a href="https://developer.mozilla.org/">Example link</a></p>
+
+</body>
+</html>
+ +

See also

+ + + +

{{ languages( {"zh-cn": "zh-cn/DOM/XMLHttpRequest/Synchronous_and_Asynchronous_Requests" } ) }}

diff --git a/files/zh-tw/web/api/xmlhttprequest/using_xmlhttprequest/index.html b/files/zh-tw/web/api/xmlhttprequest/using_xmlhttprequest/index.html new file mode 100644 index 0000000000..97b03c21d1 --- /dev/null +++ b/files/zh-tw/web/api/xmlhttprequest/using_xmlhttprequest/index.html @@ -0,0 +1,766 @@ +--- +title: 使用 XMLHttpRequest +slug: Web/API/XMLHttpRequest/Using_XMLHttpRequest +tags: + - AJAX + - AJAXfile + - Advanced + - DOM + - JXON + - MakeBrowserAgnostic + - NeedsCompatTable + - XML + - XMLHttpRequest +translation_of: Web/API/XMLHttpRequest/Using_XMLHttpRequest +--- +

要送出一個 HTTP 請求,需要建立一個 {{domxref("XMLHttpRequest")}} 物件、開啟一個 URL,並發起一個請求。在交易(transaction)完成後,XMLHttpRequest 物件將會包含如回應內容(response body)及 HTTP 狀態等等請求結果中的有用資訊。本頁概述了一些常見的、甚至略為難理解的 XMLHttpRequest 物件使用案例。

+ +
function reqListener () {
+  console.log(this.responseText);
+}
+
+var oReq = new XMLHttpRequest();
+oReq.addEventListener("load", reqListener);
+oReq.open("GET", "http://www.example.org/example.txt");
+oReq.send();
+ +

請求類型

+ +

透過 XMLHttpRequest 建立的請求,其取得資料的方式可以為非同步(asynchronously)或同步(synchronously)兩種之一。請求的種類是由 {{domxref("XMLHttpRequest.open()")}} 方法的選擇性參數 async(第三個參數)決定。若 async 參數為 true 或是未指定,XMLHttpRequest 會被設定為非同步,相反的若為 false 則會被設定為同步。這兩種請求類型的細節討論與示範可以在同步與非同步請求頁面中找到。一般來說,很少會使用到同步請求。

+ +
備註:自 Gecko 30.0 {{ geckoRelease("30.0") }} 開始,在主執行緒上的同步請求因其差勁的使用者體驗已被棄用。
+ +

處理回應

+ +

XMLHttpRequest 的活動標準規範(living standard specification)定義了數個 XMLHttpRequest 建構出之物件的回應屬性。這些回應屬性告訴客戶端關於 XMLHttpRequest 回應狀態的重要資訊。一些處理非文字類型回應的案例可能會需要一些在下面小節所說明的分析和操作。

+ +

分析及操作 responseXML 屬性

+ +

透過 XMLHttpRequest 取得一個遠端的 XML 文件內容時,responseXML 屬性({{Glossary("property/JavaScript", "property")}})將會是一個由 XML 文件解析而來的 DOM 物件。這可能會造成分析和操作上的一些困難,以下有四種主要的 XML 文件分析方式:

+ +
    +
  1. 利用 XPath 指向需要部份。
  2. +
  3. 手動的解析與序列化 XML 成字串或物件。
  4. +
  5. 利用 {{domxref("XMLSerializer")}} 來序列化 DOM 樹成字串或檔案
  6. +
  7. 如果事先知道 XML 文件內容,可利用 {{jsxref("RegExp")}}。如果換行符號會影響 RegExp 掃描結果,則需要移除換行符號。然而,這項方式應該是「最後不得已的手段(last resort)」,因為一旦 XML 文件內容稍有變動,此方式就可能會失敗。
  8. +
+ +

分析及操作含有 HTML 文件的 responseText 屬性

+ +
備註:W3C 的XMLHttpRequest 規範允許透過 XMLHttpRequest.responseXML 屬性({{Glossary("property/JavaScript", "property")}})來解析 HTML。相關細節請參考 HTML in XMLHttpRequest 一文。
+ +

若透過 XMLHttpRequest 來取得一個遠端的 HTML 網頁內容,則 responseText 屬性({{Glossary("property/JavaScript", "property")}})會是「一串(soup)」包含所有 HTML 標籤的字串。這可能使得在分析和操作上造成困難,以下有三種主要分析此一大串 HTML 字串的方式:

+ +
    +
  1. 利用 XMLHttpRequest.responseXML 屬性。
  2. +
  3. 將內容透過 fragment.body.innerHTML 注入文件片段(document fragment)body 中,並遍歷(traverse)文件片段的 DOM。
  4. +
  5. 如果事先知道 HTML 之 responseText 內容,可利用 {{jsxref("RegExp")}}。如果換行符號會影響 RegExp 掃描結果,則需要移除換行符號。然而,這項方式應該是「最後不得已的手段(last resort)」,因為一旦 HTML 程式碼稍有變動,此方式就可能會失敗。
  6. +
+ +

處理二進位資料

+ +

僅管 XMLHttpRequest 最常被用在傳送及接收文字資料,但它其實也可以傳送及接收二進位內容。有幾種經過良好測試的方法可以用來強制使用 XMLHttpRequest 發送二進位資料。透過使用 XMLHttpRequest 物件的 .overrideMimeType() 方法是一個可行的解決方案。

+ +
var oReq = new XMLHttpRequest();
+oReq.open("GET", url);
+// retrieve data unprocessed as a binary string
+oReq.overrideMimeType("text/plain; charset=x-user-defined");
+/* ... */
+
+ +

XMLHttpRequest Level 2 規範加入了新的 responseType 屬性,讓收發二進位資料變得容易許多。

+ +
var oReq = new XMLHttpRequest();
+
+oReq.onload = function(e) {
+  var arraybuffer = oReq.response; // not responseText
+  /* ... */
+}
+oReq.open("GET", url);
+oReq.responseType = "arraybuffer";
+oReq.send();
+ +

更多的範例可參考傳送及接收二進位資料頁面。

+ +

監視進度

+ +

XMLHttpRequest 提供了監聽請求於處理過程中所發生的各項事件之能力。包括了定期進度通知、錯誤通知等等。

+ +

XMLHttpRequest 支援可監視其傳輸進度的 DOM 進度事件,此事件遵循進度事件規範:這些事件實作了 {{domxref("ProgressEvent")}} 介面。

+ +
var oReq = new XMLHttpRequest();
+
+oReq.addEventListener("progress", updateProgress);
+oReq.addEventListener("load", transferComplete);
+oReq.addEventListener("error", transferFailed);
+oReq.addEventListener("abort", transferCanceled);
+
+oReq.open();
+
+// ...
+
+// progress on transfers from the server to the client (downloads)
+function updateProgress (oEvent) {
+  if (oEvent.lengthComputable) {
+    var percentComplete = oEvent.loaded / oEvent.total;
+    // ...
+  } else {
+    // Unable to compute progress information since the total size is unknown
+  }
+}
+
+function transferComplete(evt) {
+  console.log("The transfer is complete.");
+}
+
+function transferFailed(evt) {
+  console.log("An error occurred while transferring the file.");
+}
+
+function transferCanceled(evt) {
+  console.log("The transfer has been canceled by the user.");
+}
+ +

第 3-6 行加入了事件監聽器來處理使用 XMLHttpRequest 執行資料收發過程中的各類事件。

+ +
備註:必須在呼叫 open() 方法開啟請求連線之前就註冊好事件監聽器,否則 progress 事件將不會被觸發。
+ +

在這個例子中,指定了 updateProgress() 函式作為 progress 事件處理器,progress 事件處理器會於 progress 事件物件的 totalloaded 屬性分別接收到要傳輸的總位元數及已送出的位元數。然而,假如 lengthComputable 屬性值為假,則代表要傳輸的總位元數是未知且 total 屬性值將會為零。

+ +

progress 事件同時存在於上傳及下載傳輸中。下載的相關事件會於 XMLHttpRequest 物件自己身上被觸發,如上面的範例。而上傳相關事件則在 XMLHttpRequest.upload 物件上被觸發,如以下範例:

+ +
var oReq = new XMLHttpRequest();
+
+oReq.upload.addEventListener("progress", updateProgress);
+oReq.upload.addEventListener("load", transferComplete);
+oReq.upload.addEventListener("error", transferFailed);
+oReq.upload.addEventListener("abort", transferCanceled);
+
+oReq.open();
+
+ +
備註:progress 事件無法用於 file: 通訊協定。
+ +
+

備註:自 {{Gecko("9.0")}} 開始,接收到每一個資料的區塊(chunk)時,progress 事件都會被觸發。包括在 progress 事件被觸發前,就已經接收到含有最後一個資料區塊的最後一個封包並且關閉連線的狀況下,在載入此封包時仍會自動觸發 progress 事件。這代表我們可以僅關注 progress 事件即能夠可靠的監視進度。

+
+ +
+

備註:在 {{Gecko("12.0")}} 中,如果 XMLHttpRequestresponseType 屬性為「moz-blob」,那麼 progress 事件觸發時的 XMLHttpRequest.response 值會是一個目前包含了所接收資料的 {{domxref("Blob")}}。

+
+ +

我們也可以透過 loadend 事件來偵測到所有之三種下載結束狀況(abortloaderror):

+ +
req.addEventListener("loadend", loadEnd);
+
+function loadEnd(e) {
+  console.log("The transfer finished (although we don't know if it succeeded or not).");
+}
+
+ +

請注意由 loadend 事件中接收到的資訊並無法確定是由何種結束狀況所觸發。不過還是可以用 loadend 事件來處理所有傳輸結束情況下需要執行的任務。

+ +

提交表單與上傳檔案

+ +

XMLHttpRequest 物件實體有兩種方式來提交表單:

+ + + +

使用 FormData API 是最簡單、快速的方式,但不利於將資料集合進行字串化
+ 只使用 AJAX 的方式較為複雜,但也更加靈活、強大。

+ +

僅使用 XMLHttpRequest

+ +

以不透過 FormData API 提交表單的方式在大多數的情況下都不需要使用其他額外的 API。唯一的例外是要上傳一或多個檔案時,會需要用到 {{domxref("FileReader")}} API。

+ +

提交方法簡介

+ +

一個 HTML {{HTMLElement("form", "表單(form)")}}有以下四種提交方式:

+ + + +

現在,假設要提交一個只包含兩個欄位的表單,欄位名稱為 foobaz。若是使用 POST 方法,伺服器將會收到一個如以下三個例子之一的字串,這取決於所使用的編碼類型(encoding type):

+ + + +

如果是使用 GET 方法,一個如下方的字串會被直接附加入到 URL 上:

+ +
?foo=bar&baz=The%20first%20line.%0AThe%20second%20line.
+ +

小型原生框架

+ +

在我們提交 {{HTMLElement("form")}} 時,瀏覽器自動幫我們做了上面這些工作。假如要使用 JavaScript 達到同樣的效果就必須告訴直譯器(interpreter)要處理的所有事。然而,如何透過純粹的 AJAX 來傳送表單複雜到難以在本頁解釋所有細節。基於這個理由,我們改為在這此提供一組完整(教學用)的框架,可用於上述四種的每一種提交(submit),並包括上傳檔案

+ +
+
<!doctype html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title>Sending forms with pure AJAX &ndash; MDN</title>
+<script type="text/javascript">
+
+"use strict";
+
+/*\
+|*|
+|*|  :: XMLHttpRequest.prototype.sendAsBinary() Polyfill ::
+|*|
+|*|  https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#sendAsBinary()
+\*/
+
+if (!XMLHttpRequest.prototype.sendAsBinary) {
+  XMLHttpRequest.prototype.sendAsBinary = function(sData) {
+    var nBytes = sData.length, ui8Data = new Uint8Array(nBytes);
+    for (var nIdx = 0; nIdx < nBytes; nIdx++) {
+      ui8Data[nIdx] = sData.charCodeAt(nIdx) & 0xff;
+    }
+    /* send as ArrayBufferView...: */
+    this.send(ui8Data);
+    /* ...or as ArrayBuffer (legacy)...: this.send(ui8Data.buffer); */
+  };
+}
+
+/*\
+|*|
+|*|  :: AJAX Form Submit Framework ::
+|*|
+|*|  https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest
+|*|
+|*|  This framework is released under the GNU Public License, version 3 or later.
+|*|  https://www.gnu.org/licenses/gpl-3.0-standalone.html
+|*|
+|*|  Syntax:
+|*|
+|*|   AJAXSubmit(HTMLFormElement);
+\*/
+
+var AJAXSubmit = (function () {
+
+  function ajaxSuccess () {
+    /* console.log("AJAXSubmit - Success!"); */
+    console.log(this.responseText);
+    /* you can get the serialized data through the "submittedData" custom property: */
+    /* console.log(JSON.stringify(this.submittedData)); */
+  }
+
+  function submitData (oData) {
+    /* the AJAX request... */
+    var oAjaxReq = new XMLHttpRequest();
+    oAjaxReq.submittedData = oData;
+    oAjaxReq.onload = ajaxSuccess;
+    if (oData.technique === 0) {
+      /* method is GET */
+      oAjaxReq.open("get", oData.receiver.replace(/(?:\?.*)?$/,
+          oData.segments.length > 0 ? "?" + oData.segments.join("&") : ""), true);
+      oAjaxReq.send(null);
+    } else {
+      /* method is POST */
+      oAjaxReq.open("post", oData.receiver, true);
+      if (oData.technique === 3) {
+        /* enctype is multipart/form-data */
+        var sBoundary = "---------------------------" + Date.now().toString(16);
+        oAjaxReq.setRequestHeader("Content-Type", "multipart\/form-data; boundary=" + sBoundary);
+        oAjaxReq.sendAsBinary("--" + sBoundary + "\r\n" +
+            oData.segments.join("--" + sBoundary + "\r\n") + "--" + sBoundary + "--\r\n");
+      } else {
+        /* enctype is application/x-www-form-urlencoded or text/plain */
+        oAjaxReq.setRequestHeader("Content-Type", oData.contentType);
+        oAjaxReq.send(oData.segments.join(oData.technique === 2 ? "\r\n" : "&"));
+      }
+    }
+  }
+
+  function processStatus (oData) {
+    if (oData.status > 0) { return; }
+    /* the form is now totally serialized! do something before sending it to the server... */
+    /* doSomething(oData); */
+    /* console.log("AJAXSubmit - The form is now serialized. Submitting..."); */
+    submitData (oData);
+  }
+
+  function pushSegment (oFREvt) {
+    this.owner.segments[this.segmentIdx] += oFREvt.target.result + "\r\n";
+    this.owner.status--;
+    processStatus(this.owner);
+  }
+
+  function plainEscape (sText) {
+    /* How should I treat a text/plain form encoding?
+       What characters are not allowed? this is what I suppose...: */
+    /* "4\3\7 - Einstein said E=mc2" ----> "4\\3\\7\ -\ Einstein\ said\ E\=mc2" */
+    return sText.replace(/[\s\=\\]/g, "\\$&");
+  }
+
+  function SubmitRequest (oTarget) {
+    var nFile, sFieldType, oField, oSegmReq, oFile, bIsPost = oTarget.method.toLowerCase() === "post";
+    /* console.log("AJAXSubmit - Serializing form..."); */
+    this.contentType = bIsPost && oTarget.enctype ? oTarget.enctype : "application\/x-www-form-urlencoded";
+    this.technique = bIsPost ?
+        this.contentType === "multipart\/form-data" ? 3 : this.contentType === "text\/plain" ? 2 : 1 : 0;
+    this.receiver = oTarget.action;
+    this.status = 0;
+    this.segments = [];
+    var fFilter = this.technique === 2 ? plainEscape : escape;
+    for (var nItem = 0; nItem < oTarget.elements.length; nItem++) {
+      oField = oTarget.elements[nItem];
+      if (!oField.hasAttribute("name")) { continue; }
+      sFieldType = oField.nodeName.toUpperCase() === "INPUT" ? oField.getAttribute("type").toUpperCase() : "TEXT";
+      if (sFieldType === "FILE" && oField.files.length > 0) {
+        if (this.technique === 3) {
+          /* enctype is multipart/form-data */
+          for (nFile = 0; nFile < oField.files.length; nFile++) {
+            oFile = oField.files[nFile];
+            oSegmReq = new FileReader();
+            /* (custom properties:) */
+            oSegmReq.segmentIdx = this.segments.length;
+            oSegmReq.owner = this;
+            /* (end of custom properties) */
+            oSegmReq.onload = pushSegment;
+            this.segments.push("Content-Disposition: form-data; name=\"" +
+                oField.name + "\"; filename=\"" + oFile.name +
+                "\"\r\nContent-Type: " + oFile.type + "\r\n\r\n");
+            this.status++;
+            oSegmReq.readAsBinaryString(oFile);
+          }
+        } else {
+          /* enctype is application/x-www-form-urlencoded or text/plain or
+             method is GET: files will not be sent! */
+          for (nFile = 0; nFile < oField.files.length;
+              this.segments.push(fFilter(oField.name) + "=" + fFilter(oField.files[nFile++].name)));
+        }
+      } else if ((sFieldType !== "RADIO" && sFieldType !== "CHECKBOX") || oField.checked) {
+        /* NOTE: this will submit _all_ submit buttons. Detecting the correct one is non-trivial. */
+        /* field type is not FILE or is FILE but is empty */
+        this.segments.push(
+          this.technique === 3 ? /* enctype is multipart/form-data */
+            "Content-Disposition: form-data; name=\"" + oField.name + "\"\r\n\r\n" + oField.value + "\r\n"
+          : /* enctype is application/x-www-form-urlencoded or text/plain or method is GET */
+            fFilter(oField.name) + "=" + fFilter(oField.value)
+        );
+      }
+    }
+    processStatus(this);
+  }
+
+  return function (oFormElement) {
+    if (!oFormElement.action) { return; }
+    new SubmitRequest(oFormElement);
+  };
+
+})();
+
+</script>
+</head>
+<body>
+
+<h1>Sending forms with pure AJAX</h1>
+
+<h2>Using the GET method</h2>
+
+<form action="register.php" method="get" onsubmit="AJAXSubmit(this); return false;">
+  <fieldset>
+    <legend>Registration example</legend>
+    <p>
+      First name: <input type="text" name="firstname" /><br />
+      Last name: <input type="text" name="lastname" />
+    </p>
+    <p>
+      <input type="submit" value="Submit" />
+    </p>
+  </fieldset>
+</form>
+
+<h2>Using the POST method</h2>
+<h3>Enctype: application/x-www-form-urlencoded (default)</h3>
+
+<form action="register.php" method="post" onsubmit="AJAXSubmit(this); return false;">
+  <fieldset>
+    <legend>Registration example</legend>
+    <p>
+      First name: <input type="text" name="firstname" /><br />
+      Last name: <input type="text" name="lastname" />
+    </p>
+    <p>
+      <input type="submit" value="Submit" />
+    </p>
+  </fieldset>
+</form>
+
+<h3>Enctype: text/plain</h3>
+
+<form action="register.php" method="post" enctype="text/plain"
+    onsubmit="AJAXSubmit(this); return false;">
+  <fieldset>
+    <legend>Registration example</legend>
+    <p>
+      Your name: <input type="text" name="user" />
+    </p>
+    <p>
+      Your message:<br />
+      <textarea name="message" cols="40" rows="8"></textarea>
+    </p>
+    <p>
+      <input type="submit" value="Submit" />
+    </p>
+  </fieldset>
+</form>
+
+<h3>Enctype: multipart/form-data</h3>
+
+<form action="register.php" method="post" enctype="multipart/form-data"
+    onsubmit="AJAXSubmit(this); return false;">
+  <fieldset>
+    <legend>Upload example</legend>
+    <p>
+      First name: <input type="text" name="firstname" /><br />
+      Last name: <input type="text" name="lastname" /><br />
+      Sex:
+      <input id="sex_male" type="radio" name="sex" value="male" />
+      <label for="sex_male">Male</label>
+      <input id="sex_female" type="radio" name="sex" value="female" />
+      <label for="sex_female">Female</label><br />
+      Password: <input type="password" name="secret" /><br />
+      What do you prefer:
+      <select name="image_type">
+        <option>Books</option>
+        <option>Cinema</option>
+        <option>TV</option>
+      </select>
+    </p>
+    <p>
+      Post your photos:
+      <input type="file" multiple name="photos[]">
+    </p>
+    <p>
+      <input id="vehicle_bike" type="checkbox" name="vehicle[]" value="Bike" />
+      <label for="vehicle_bike">I have a bike</label><br />
+      <input id="vehicle_car" type="checkbox" name="vehicle[]" value="Car" />
+      <label for="vehicle_car">I have a car</label>
+    </p>
+    <p>
+      Describe yourself:<br />
+      <textarea name="description" cols="50" rows="8"></textarea>
+    </p>
+    <p>
+      <input type="submit" value="Submit" />
+    </p>
+  </fieldset>
+</form>
+
+</body>
+</html>
+
+ +

為了進行測試,建立一個名為 register.php 的 PHP 頁面(即為上面範例表單之 action 屬性({{Glossary("attribute")}})所指向的位置),並輸入以下最簡化的內容:

+ +
<?php
+/* register.php */
+
+header("Content-type: text/plain");
+
+/*
+NOTE: You should never use `print_r()` in production scripts, or
+otherwise output client-submitted data without sanitizing it first.
+Failing to sanitize can lead to cross-site scripting vulnerabilities.
+*/
+
+echo ":: data received via GET ::\n\n";
+print_r($_GET);
+
+echo "\n\n:: Data received via POST ::\n\n";
+print_r($_POST);
+
+echo "\n\n:: Data received as \"raw\" (text/plain encoding) ::\n\n";
+if (isset($HTTP_RAW_POST_DATA)) { echo $HTTP_RAW_POST_DATA; }
+
+echo "\n\n:: Files received ::\n\n";
+print_r($_FILES);
+
+
+ +

使用這個框架的語法簡單如下:

+ +
AJAXSubmit(myForm);
+ +
備註:此框架使用了 {{domxref("FileReader")}} API 來發送檔案上傳。這是個較新的 API,且 IE9 或其先前版本並未實作。因為這個理由,AJAX-only 上傳被認為是一項實驗性技術。若沒有需要上傳二進位檔案,此框架可於大部分瀏覽器中運作良好。
+ +
備註:傳送二進位檔案的最佳方式是藉由 {{jsxref("ArrayBuffer", "ArrayBuffers")}} 或 {{domxref("Blob", "Blobs")}} 結合 {{domxref("XMLHttpRequest.send()", "send()")}} 方法來送出,如果可以也能搭配 FileReader API 的 {{domxref("FileReader.readAsArrayBuffer()", "readAsArrayBuffer()")}} 方法先進行讀取。但因為這段程式指令碼(script)的目的是要處理可字串化的原始資料,所以使用 {{domxref("XMLHttpRequest.sendAsBinary()", "sendAsBinary()")}} 方法結合 FileReader API 的 {{domxref("FileReader.readAsBinaryString()", "readAsBinaryString()")}} 方法。就其本身來看,以上的指令碼只有在處理小型檔案時才有意義。假如不打算上傳二進位內容,請考慮使用 FormData API。
+ +
備註:非標準的 sendAsBinary 方法在 Gecko 31 {{geckoRelease(31)}} 已被認為是棄用的(deprecated),並且即將被移除。而標準的 send(Blob data) 方法可以作為替代。
+ +

使用 FormData 物件

+ +

{{domxref("XMLHttpRequest.FormData", "FormData")}} 建構式可以讓我們收集一連串名/值對資料並透過 XMLHttpRequest 送出。其主要用於傳送表單資料,但也能夠單獨的由表單建立來傳輸使用者輸入的資料。若表單的編碼類型(encoding type)被設定為「multipart/form-data」,則由 FormData 所發送的資料格式和表單用來傳送資料的 submit() 方法相同。FormData 物件可以搭配 XMLHttpRequest 以多種方式使用。相關的範例,以及可以怎麼利用 FormData 配合 XMLHttpRequest 的說明,請參考使用 FormData 物件頁面。為了教學使用,下方為一個利用 FormData API 來改寫先前範例翻譯版本。注意這段精簡後的程式碼:

+ +
+
<!doctype html>
+<html>
+<head>
+<meta http-equiv="Content-Type" charset="UTF-8" />
+<title>Sending forms with FormData &ndash; MDN</title>
+<script>
+"use strict";
+
+function ajaxSuccess () {
+  console.log(this.responseText);
+}
+
+function AJAXSubmit (oFormElement) {
+  if (!oFormElement.action) { return; }
+  var oReq = new XMLHttpRequest();
+  oReq.onload = ajaxSuccess;
+  if (oFormElement.method.toLowerCase() === "post") {
+    oReq.open("post", oFormElement.action);
+    oReq.send(new FormData(oFormElement));
+  } else {
+    var oField, sFieldType, nFile, sSearch = "";
+    for (var nItem = 0; nItem < oFormElement.elements.length; nItem++) {
+      oField = oFormElement.elements[nItem];
+      if (!oField.hasAttribute("name")) { continue; }
+      sFieldType = oField.nodeName.toUpperCase() === "INPUT" ?
+          oField.getAttribute("type").toUpperCase() : "TEXT";
+      if (sFieldType === "FILE") {
+        for (nFile = 0; nFile < oField.files.length;
+            sSearch += "&" + escape(oField.name) + "=" + escape(oField.files[nFile++].name));
+      } else if ((sFieldType !== "RADIO" && sFieldType !== "CHECKBOX") || oField.checked) {
+        sSearch += "&" + escape(oField.name) + "=" + escape(oField.value);
+      }
+    }
+    oReq.open("get", oFormElement.action.replace(/(?:\?.*)?$/, sSearch.replace(/^&/, "?")), true);
+    oReq.send(null);
+  }
+}
+</script>
+</head>
+<body>
+
+<h1>Sending forms with FormData</h1>
+
+<h2>Using the GET method</h2>
+
+<form action="register.php" method="get" onsubmit="AJAXSubmit(this); return false;">
+  <fieldset>
+    <legend>Registration example</legend>
+    <p>
+      First name: <input type="text" name="firstname" /><br />
+      Last name: <input type="text" name="lastname" />
+    </p>
+    <p>
+      <input type="submit" value="Submit" />
+    </p>
+  </fieldset>
+</form>
+
+<h2>Using the POST method</h2>
+<h3>Enctype: application/x-www-form-urlencoded (default)</h3>
+
+<form action="register.php" method="post" onsubmit="AJAXSubmit(this); return false;">
+  <fieldset>
+    <legend>Registration example</legend>
+    <p>
+      First name: <input type="text" name="firstname" /><br />
+      Last name: <input type="text" name="lastname" />
+    </p>
+    <p>
+      <input type="submit" value="Submit" />
+    </p>
+  </fieldset>
+</form>
+
+<h3>Enctype: text/plain</h3>
+
+<p>The text/plain encoding is not supported by the FormData API.</p>
+
+<h3>Enctype: multipart/form-data</h3>
+
+<form action="register.php" method="post" enctype="multipart/form-data"
+    onsubmit="AJAXSubmit(this); return false;">
+  <fieldset>
+    <legend>Upload example</legend>
+    <p>
+      First name: <input type="text" name="firstname" /><br />
+      Last name: <input type="text" name="lastname" /><br />
+      Sex:
+      <input id="sex_male" type="radio" name="sex" value="male" />
+      <label for="sex_male">Male</label>
+      <input id="sex_female" type="radio" name="sex" value="female" />
+      <label for="sex_female">Female</label><br />
+      Password: <input type="password" name="secret" /><br />
+      What do you prefer:
+      <select name="image_type">
+        <option>Books</option>
+        <option>Cinema</option>
+        <option>TV</option>
+      </select>
+    </p>
+    <p>
+      Post your photos:
+      <input type="file" multiple name="photos[]">
+    </p>
+    <p>
+      <input id="vehicle_bike" type="checkbox" name="vehicle[]" value="Bike" />
+      <label for="vehicle_bike">I have a bike</label><br />
+      <input id="vehicle_car" type="checkbox" name="vehicle[]" value="Car" />
+      <label for="vehicle_car">I have a car</label>
+    </p>
+    <p>
+      Describe yourself:<br />
+      <textarea name="description" cols="50" rows="8"></textarea>
+    </p>
+    <p>
+      <input type="submit" value="Submit" />
+    </p>
+  </fieldset>
+</form>
+</body>
+</html>
+
+ +
備註:如同之前所說,{{domxref("FormData")}} 物件是不能被字串化的物件。若想要字串化一個被提交的資料,請使用先前的 AJAX 範例。還要注意的是,雖然在這個例子中有一些 file {{ HTMLElement("input") }} 欄位,當你透過 FormData API 來提交表單便也不需要使用 {{domxref("FileReader")}} API:檔案會自動地載入並上傳。
+ +

取得最後修改日期

+ +
function getHeaderTime () {
+  console.log(this.getResponseHeader("Last-Modified"));  /* A valid GMTString date or null */
+}
+
+var oReq = new XMLHttpRequest();
+oReq.open("HEAD" /* use HEAD if you only need the headers! */, "yourpage.html");
+oReq.onload = getHeaderTime;
+oReq.send();
+ +

當最後修改日期改變時做一些事

+ +

先建立兩個函式:

+ +
function getHeaderTime () {
+  var nLastVisit = parseFloat(window.localStorage.getItem('lm_' + this.filepath));
+  var nLastModif = Date.parse(this.getResponseHeader("Last-Modified"));
+
+  if (isNaN(nLastVisit) || nLastModif > nLastVisit) {
+    window.localStorage.setItem('lm_' + this.filepath, Date.now());
+    isFinite(nLastVisit) && this.callback(nLastModif, nLastVisit);
+  }
+}
+
+function ifHasChanged(sURL, fCallback) {
+  var oReq = new XMLHttpRequest();
+  oReq.open("HEAD" /* use HEAD - we only need the headers! */, sURL);
+  oReq.callback = fCallback;
+  oReq.filepath = sURL;
+  oReq.onload = getHeaderTime;
+  oReq.send();
+}
+ +

並進行測試:

+ +
/* Let's test the file "yourpage.html"... */
+
+ifHasChanged("yourpage.html", function (nModif, nVisit) {
+  console.log("The page '" + this.filepath + "' has been changed on " + (new Date(nModif)).toLocaleString() + "!");
+});
+ +

如果想要知道目前頁面是否已變更,請參考 {{domxref("document.lastModified")}} 一文。

+ +

跨網域 XMLHttpRequest

+ +

現代瀏覽器支援跨網域(cross-site)請求並實作了網路應用程式工作小組(Web Applications (WebApps) Working Group)提出的跨網域請求存取控制標準。只要伺服器被設定為允許來自你的網路應用程式來源(origin)網域之請求,XMLHttpRequest 便能正常運作。否則,將會拋出一個 INVALID_ACCESS_ERR 例外。

+ +

避開快取

+ +

有一個跨瀏覽器相容的避開快取方法,便是將時間戳記(timestamp)附加於 URL 後方,請確保加上了適當的「?」或「&」。例如:

+ +
http://foo.com/bar.html -> http://foo.com/bar.html?12345
+http://foo.com/bar.html?foobar=baz -> http://foo.com/bar.html?foobar=baz&12345
+
+ +

由於本地快取的索引是基於 URL,加入時間戳記會導致每一個請求都會是唯一的,藉此避開快取。

+ +

可以使用以下的程式碼來自動的調整 URL:

+ +
var oReq = new XMLHttpRequest();
+
+oReq.open("GET", url + ((/\?/).test(url) ? "&" : "?") + (new Date()).getTime());
+oReq.send(null);
+ +

安全性

+ +

{{fx_minversion_note(3, "Firefox 3 之前的版本允許在偏好設定中設定 capability.policy.<policyname>.XMLHttpRequest.open</policyname>allAccess 來讓指定的網域能夠跨網域存取。現已不再支援。")}}

+ +

{{fx_minversion_note(5, "Firefox 5 之前的版本可以使用 netscape.security.PrivilegeManager.enablePrivilege(\"UniversalBrowserRead\"); 來發送跨網域存取請求。現已不再支援,即使它不會有警告並且依然會顯示允許請求的權限對話框。")}}

+ +

開啟跨網域指令碼(script)的建議方式是於 XMLHttpRequest 的回應中使用 Access-Control-Allow-Origin HTTP 標頭。

+ +

被中止的 XMLHttpRequest

+ +

如果你發現 XMLHttpRequeststatus=0statusText=null,這代表請求並不被允許執行,其狀態為 UNSENT(未送出)。被中止的原因可能是因為 XMLHttpRequest 物件所關聯的 origin(來源網域)值(於 XMLHttpRequest 物件建立時自 window.origin 取得)在呼叫 open() 方法之前就已經被改變。這是可能發生的,例如在 windowonunload 事件觸發時送出 XMLHttpRequest 請求,預期的情況為:XMLHttpRequest 物件剛被建立,而目前的視窗尚未關閉,而最後發送請求(即呼叫了 open() 方法)的時間點是在此視窗失去了焦點並且另外的視窗取得焦點之間。要避開這個問題的最有效方法是在要被終止的(terminated)window 觸發 unload 事件時,於新的 window 的上註冊一個新的 activate 事件監聽器來發送請求。

+ +

使用 JavaScript 模組/XPCOM 元件中的 XMLHttpRequest

+ +

JavaScript 模組 或 XPCOM 元件實體化一個 XMLHttpRequest 物件在做法上會有些許不同;我們無法用 XMLHttpRequest() 建構式,因為此建構式並未在元件中定義,並會導致程式產生錯誤。較佳的方式是使用 XPCOM 元件的建構式。

+ +
const XMLHttpRequest = Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1",
+    "nsIXMLHttpRequest");
+
+ +

在 Gecko 16 之前,存在著一個透過這種方式發送的請求會被無條件取消的臭蟲。若程式需要在 Gecko 15 或更早的版本上運作,可以從隱藏的 DOM window 中取得 XMLHttpRequest() 建構式。

+ +
const { XMLHttpRequest } = Components.classes["@mozilla.org/appshell/appShellService;1"]
+                                     .getService(Components.interfaces.nsIAppShellService)
+                                     .hiddenDOMWindow;
+var oReq = new XMLHttpRequest();
+ +

參見

+ +
    +
  1. MDN AJAX 介紹
  2. +
  3. HTTP 存取控制
  4. +
  5. How to check the security state of an XMLHTTPRequest over SSL
  6. +
  7. XMLHttpRequest - REST and the Rich User Experience
  8. +
  9. Microsoft documentation
  10. +
  11. Apple developers' reference
  12. +
  13. "Using the XMLHttpRequest Object" (jibbering.com)
  14. +
  15. The XMLHttpRequest object: WHATWG specification
  16. +
diff --git a/files/zh-tw/web/api/xmlhttprequest/withcredentials/index.html b/files/zh-tw/web/api/xmlhttprequest/withcredentials/index.html new file mode 100644 index 0000000000..e70f611ece --- /dev/null +++ b/files/zh-tw/web/api/xmlhttprequest/withcredentials/index.html @@ -0,0 +1,48 @@ +--- +title: XMLHttpRequest.withCredentials +slug: Web/API/XMLHttpRequest/withCredentials +translation_of: Web/API/XMLHttpRequest/withCredentials +--- +
{{APIRef('XMLHttpRequest')}}
+ +

XMLHttpRequest.withCredentials 屬性是一個 {{jsxref("Boolean")}} 型別,它指出無論是否使用 Access-Control 標頭在跨站的要求上,都應該使用像 Cookies、Authorization 標頭或 TLS 用戶端憑證來進行驗證。在相同來源的要求設定 withCredentials 沒有任何效果。

+ +

In addition, this flag is also used to indicate when cookies are to be ignored in the response. The default is false. XMLHttpRequest from a different domain cannot set cookie values for their own domain unless withCredentials is set to true before making the request. The third-party cookies obtained by setting withCredentials to true will still honor same-origin policy and hence can not be accessed by the requesting script through document.cookie or from response headers.

+ +
+

Note: 永遠不會影響到同源請求。

+
+ +
+

Note: XMLHttpRequest responses from a different domain cannot set cookie values for their own domain unless withCredentials is set to true before making the request, regardless of Access-Control- header values. 

+
+ +

範例

+ +
var xhr = new XMLHttpRequest();
+xhr.open('GET', 'http://example.com/', true);
+xhr.withCredentials = true;
+xhr.send(null);
+ +

規格

+ + + + + + + + + + + + + + +
規格狀態備註
{{SpecName('XMLHttpRequest', '#the-withcredentials-attribute')}}{{Spec2('XMLHttpRequest')}}WHATWG living standard
+ +

瀏覽器相容性

+ + + +

{{Compat("api.XMLHttpRequest.withCredentials")}}

diff --git a/files/zh-tw/web/api/xmlhttprequest/xmlhttprequest/index.html b/files/zh-tw/web/api/xmlhttprequest/xmlhttprequest/index.html new file mode 100644 index 0000000000..6459ef0c2a --- /dev/null +++ b/files/zh-tw/web/api/xmlhttprequest/xmlhttprequest/index.html @@ -0,0 +1,50 @@ +--- +title: XMLHttpRequest() +slug: Web/API/XMLHttpRequest/XMLHttpRequest +translation_of: Web/API/XMLHttpRequest/XMLHttpRequest +--- +
{{draft}}{{APIRef('XMLHttpRequest')}}
+ +

XMLHttpRequest() 建構式會建立一個新的 {{domxref("XMLHttpRequest")}} 物件。

+ +

關於如何使用 XMLHttpRequest 物件的細節,請參照: Using XMLHttpRequest.

+ +

語法

+ +
const request = new XMLHttpRequest();
+
+ +

參數

+ +

無。

+ +

回傳值 

+ +

將回傳一個新的 {{domxref("XMLHttpRequest")}} 物件。{{domxref("XMLHttpRequest")}} 物件在呼叫{{domxref("XMLHttpRequest.send", "send()")}} 送出要求到伺服器之前,至少要藉著呼叫 {{domxref("XMLHttpRequest.open", "open()")}} 來準備好必需的設定。

+ +

非標準的 Firefox 語法

+ +

Firefox 16 added a non-standard parameter to the constructor that can enable anonymous mode (see {{Bug("692677")}}). Setting the mozAnon flag to true effectively resembles the AnonXMLHttpRequest() constructor described in older versions of the XMLHttpRequest specification.

+ +
const request = new XMLHttpRequest(paramsDictionary);
+ +

Parameters (non-standard)

+ +
+
objParameters {{gecko_minversion_inline("16.0")}}
+
There are two flags you can set: +
+
mozAnon
+
Boolean: Setting this flag to true will cause the browser not to expose the {{Glossary("origin")}} and user credentials when fetching resources. Most important, this means that {{Glossary("Cookie", "cookies")}} will not be sent unless explicitly added using setRequestHeader.
+
mozSystem
+
Boolean: Setting this flag to true allows making cross-site connections without requiring the server to opt-in using {{Glossary("CORS")}}. Requires setting mozAnon: true, i.e. this can't be combined with sending cookies or other user credentials. This only works in privileged (reviewed) apps ({{Bug("692677")}}); it does not work on arbitrary webpages loaded in Firefox
+
+
+
+ +

參見

+ + -- cgit v1.2.3-54-g00ecf