認識 AJAX,了解同步與非同步與 HTTP 狀態碼

使用流程

  1. 建立 AJAX 物件
  2. 發送請求到伺服器獲取資料
  3. 伺服器回傳資料到瀏覽器
  4. 獲取資料並進行渲染或加工處理

1. 建立 XMLHttpRequest 物件

使用 XMLHttpRequest 物件來進行 AJAX 請求,並在 console 中查看 xhr 變數的內容。

1
var xhr = new XMLHttpRequest();

XHR Object

重點readyState 的數字代表不同的狀態

readyState 數字 代表涵義
0 XMLHttpRequest 物件已建立,但尚未連結
1 已調用 open(),但尚未發送請求
2 偵測到已調用 send()
3 正在加載中,可能資料量較大
4 資料已完全獲取

2. 使用 open() 連結資料

open() 方法用來設定請求的格式、網址以及同步或非同步。

1
2
// xhr.open('格式', '讀取的網址', '同步與非同步')
xhr.open('GET', 'https://hexschool.github.io/ajaxHomework/data.json', true);
格式 代表涵義
GET 讀取資料
POST 發送資料到伺服器
同步與非同步 代表涵義
true 非同步,不會等待回應,程式碼會繼續執行
false 同步,會等待回應後再繼續執行

由於調用了 open(),此時 readyState 為 1。

Open State

3. 使用 send() 傳送資料

我們目前只需讀取資料,因此可傳送 null

1
xhr.send(null);
  • 使用 send() 後,readyState 會從 2(偵測到 send())變為 3(加載中),最終變為 4(資料獲取完成)。

Data Retrieved

4. 獲取資料

  • 非同步請求

當使用非同步時,程式碼執行速度很快,可能在資料回傳之前就打印出 console

1
2
3
4
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://hexschool.github.io/ajaxHomework/data.json', true);
xhr.send(null);
console.log('xhr資料:', xhr.responseText); // 可能會顯示空值

可以使用 onload 方法來獲取資料:

1
2
3
xhr.onload = function() {
console.log('xhr資料:', xhr.responseText);
};

再用 JSON.parse 將字串轉成物件並顯示在畫面上:

1
2
3
4
5
6
7
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://hexschool.github.io/ajaxHomework/data.json', true);
xhr.send(null);
xhr.onload = function() {
var str = JSON.parse(xhr.responseText);
document.querySelector('.text').textContent = str[0].name;
};
  • 同步請求

使用同步請求可以先獲取資料,但資料量過大會影響使用者體驗。

1
2
3
4
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://hexschool.github.io/ajaxHomework/data.json', false);
xhr.send(null);
console.log('xhr資料:', xhr.responseText);

使用 JSON.parse 來轉換並顯示資料:

1
2
var str = JSON.parse(xhr.responseText);
document.querySelector('.text1').textContent = str[0].name;

HTTP 狀態碼

狀態碼 代表涵義
200 成功 (OK)
3XX 重新導向 (Redirection)
404 找不到檔案或目錄

Cross-Origin Resource Sharing (CORS)

CORS 是一種機制,使用額外的 HTTP 標頭使得瀏覽器能夠獲取來自不同來源的資源。當請求的資源來自不同的網域、協定或通訊埠時,會建立一個跨來源 HTTP 請求。

因為安全性考量,跨來源請求受到限制。XMLHttpRequestFetch 都遵循同源政策(Same-Origin Policy),除非使用 CORS 標頭,否則只能請求與應用程式相同網域的資源。

簡而言之,在同一網域下 API 可以自由使用,但在不同網域下必須確認對方的後端是否開啟 CORS,否則會出現錯誤訊息。

CORS Error

測試 CORS 網址:cors-tester

AJAX 兩種傳送方式

  1. 傳統傳送方式
  2. JSON 傳送方式

這兩種方式的程式碼差異在於 setRequestHeaderContent-Typesend 傳送的值。

AJAX 傳統傳送方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<form action="index.html">
帳號:<input class="email" type="text" name="email" id="">
<br>
密碼:<input class="password" type="password" name="password" id="">
<br>
<input class="send" type="submit" value="send">
</form>

<script>
var xhr = new XMLHttpRequest();
var send = document.querySelector('.send');
var text = document.querySelector('.text');
send.addEventListener('click', function(e) {
e.preventDefault();
var emailVal = document.querySelector('.email').value;
var passwordVal = document.querySelector('.password').value;
xhr.open('POST', 'https://hexschool-tutorial.herokuapp.com/api/signup', true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send(`email=${emailVal}&password=${passwordVal}`);
xhr.onload = function() {
var msg = JSON.parse(xhr.response);
text.textContent = msg.message;
};
});
</script>

AJAX JSON 傳送方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<form action="index.html">
帳號:<input class="email" type="text" name="email" id="">
<br>
密碼:<input class="password" type="password" name="password" id="">
<br>
<input class="send" type="submit" value="send">
</form>

<script>
var xhr = new XMLHttpRequest();
var send = document.querySelector('.send');
var text = document.querySelector('.text');
send.addEventListener('click', function(e) {
e.preventDefault();
var data = {
email: document.querySelector('.email').value,
password: document.querySelector('.password').value,
};
xhr.open('POST', 'https://hexschool-tutorial.herokuapp.com/api/signup', true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.send(JSON.stringify(data));
xhr.onload = function() {
var msg = JSON.parse(xhr.response);
text.textContent = msg.message;
};
});
</script>

不論是傳統還是 JSON 方式,傳送結果都會一致,具體使用哪一種需依據後端工程師的需求。

AJAX Result