avatar

目錄
記錄一下 AJAX 操作的幾個方法

AJAX

(Asynchronous JavaScript and XML)的縮寫
間單來說是與伺服器進行非同步通訊,可用來自伺服器的資料更新網頁元素,綜合了多項技術的瀏覽器端網頁開發技術。可以增進使用者的操作體驗。

以下介紹幾種使用方法:

JavaScript XHR

透過 XMLHttpRequest(XHR) 物件作為實作。
它能夠在 client 端對 server 端送出 http request,使用的資料格式是 XML(這也變成時代眼淚,現今大多使用 JSON,它的格式像是 JS 中的物件),用 XMLHttpRequest() 取到的結果會是字串,要額外透過 JSON.parse() 轉成 JSON 才可以使用。

Ps.目前較少用,難以閱讀及撰寫,我們大多都會使用框架來處理這段,如 jQuery, Axio…

程式碼大概長這樣:

Code
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
28
29
30
31
32
33
34
35
36
37
38
function reqOnload () {
// 資料轉成 JSON 格式
const data = JSON.parse(this.responseText);
console.log(data)
}
function reqError (err) {
console.log('錯誤', err)
}

// 宣告一個 XHR 的物件
var Req = new XMLHttpRequest();
// 定義連線方式 true: 非同步 , false: 同步
Req.open('get', 'https://randomuser.me/api/', true);
// 送出請求
Req.send();
// 如果成功就執行 reqOnload()
Req.onload = reqOnload;
// 失敗就 reqError()
Req.onerror = reqError;

//POST(Form)

var xhr = new XMLHttpRequest();
xhr.open('post', 'http://xxx', true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send('name=Bob&password=123456');

//POST(JSON)

var account = {
name: 'Bob',
password:'123456'
}
var xhr = new XMLHttpRequest();
xhr.open('post', 'https://xxx', true);
xhr.setRequestHeader('Content-type', 'application/json');
var data = JSON.stringify(account);
xhr.send(data);

XMLHttpRequest 有各種狀態碼(readyState),能夠知道當前進行到什麼狀態。

0 : 已經產生 XMLHttpRequest,但還沒連結到要取得的網址。
1 : 用了 open() ,但還沒傳送資料過去
2 : 用了 send()
3 : loading 資料
4 : 撈回資料了,數據已接收完全

jQuery

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$.ajax({
url: "http://xxx",
// 傳送至Server的資料,必須為物件格式
data : {
datafromtestFile : $("#input").val(),
},
type: "GET",
// 傳回 JSON
dataType: 'json',
// 成功時執行函式
success: function(data) {
// 取得的遠端資料
console.log(data);
},
error: function(error) {
console.log("error:", error);
}
});

Fetch

ES6 原生方法 ,是搭配 Promise(Promise 的基本用法)來執行請求網站和請求後獲取 Response 的處理。then 作為下一步,catch 作為錯誤回應 (404, 500…)。回傳的為 ReadableStream 物件,需要使用不同資料類型使用對應方法,才能正確取得資料物件。

Code
1
2
3
4
5
6
7
8
9
10
11
fetch('http://abc.com/', {method: 'GET'})
.then((response) => {
// 這裡會得到一個 ReadableStream 的物件
console.log(response);
// 可以透過 blob(), json(), text() 轉成可用的資訊
return response.json();
}).then((jsonData) => {
console.log(jsonData);
}).catch((err) => {
console.log('錯誤:', err);
});

text():改為 response.text(),取得的資料格式將會是純字串。
blob():將資料轉為 blob 物件,像是圖片就可以做這樣的轉換(指的是圖片檔案本身)。

範例:

Code
1
2
3
4
5
6
7
8
9
10
11
12
// unsplash 上的圖片
let url = 'https://images.unsplash.com/photo-1513313778780-9ae4807465f0?auto=format&fit=crop&w=634&q=80'
fetch(url)
.then((response) => {
return response.blob();
})
.then((imageBlob) => {
let img = document.createElement('IMG')
document.querySelector('.newImg').appendChild(img);
// 將 blog 物件轉為 url
img.src = URL.createObjectURL(imageBlob);
})

用 Fetch 做 post 時,需做一些調整。將 body 所送出的資料轉純字串後才能送出。

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let url = 'https://hexschool-tutorial.herokuapp.com/api/signup';
fetch(url, {
method: 'POST',
// headers 加入 json 格式
headers: {
'Content-Type': 'application/json'
},
// body 將 json 轉字串送出
body: JSON.stringify({
email: 'lovef1232e@hexschool.com',
password: '12345678'
})
}).then((response) => {
return response.json();
}).then((jsonData) => {
console.log(jsonData);
}).catch((err) => {
console.log('錯誤:', err);
})

使用 Fetch 需要注意,只要是伺服器有正確回應,不管是什麼狀態碼,就算是 404 也會將 response 傳入 then 之後的 function 繼續執行,而不會進到 catch。

此時可以透過 response 中的 ok 來判斷狀態碼是否正常,如果是 true 則表示狀態碼在於 200~299 之間。

所以可以多加個判斷

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
fetch('http://abc.com/', {method: 'get'})
.then((response) => {
if (!response.ok) {
throw new Error(response.statusText);
}
// 這裡會得到一個 ReadableStream 的物件
console.log(response);
// 可以透過 blob(), json(), text() 轉成可用的資訊
return response.json();
}).then((jsonData) => {
console.log(jsonData);
}).catch((err) => {
console.log('錯誤:', err);
});

axios

1.依賴 ES6 Promise,若不支援請使用 Polyfill
2.支援 Promise API
3.可取消請求 (Promise 無法)
4.自動轉換 JSON
5.axios 實體建立,可統一套用 Config、管理 API

安裝

$ npm install axios

Code
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
// GET
axios.get('http://user/12345')
.then(res =>{
console.log(res);
}).catch(err => {
console.log(err);
})

// POST
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
})
.finally(() => { /* 不論失敗成功皆會執行 */
});

管理 API 方式

開新檔 api.js

Code
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
28
import axios from 'axios';

// User相關的 api
const userRequest = axios.create({
baseURL: 'https://api/user/'
});
// 文章相關的 api
const articleRequest = axios.create({
baseURL: 'https://api/article/'
});
// 搜尋相關的 api
const searchRequest = axios.create({
baseURL: 'https://api/search/'
});

// User 相關的 api
export const apiUserLogin = data => userRequest.post('/signIn', data);
export const apiUserLogout = data => userRequest.post('/signOut', data);
export const apiUserSignUp = data => userRequest.post('/signUp', data);

// 文章相關的 api
export const apiArticleItem = () => articleRequest.get('/ArticleItem');
export const apiArticleMsg = data => articleRequest.post('/ArticleMsg', data);
export const apiArticleLink = data => articleRequest.post('/ArticleLink', data);

// 搜尋相關的 api
export const apiSearch = data => searchRequest.get(`/Search?searchdata=${data}`);
export const apiSearchType = () => searchRequest.get(`/SearchType`);

如果需要用到的話,就 import

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// import api.js
import { apiUserLogin, apiUserLogout, apiUserSignUp } from "api.js";

// 使用 Login
apiUserLogin({
email: "mike@gmail.com",
password: "123456789"
})
.then(res=> {
console.log(res);
})
.catch(err=> {
console.log(err);
})

參考:
axios 默認值 & 建立實體 & 錯誤偵測
鐵人賽:ES6 原生 Fetch 遠端資料方法
使用Axios你的API都怎麼管理?
Day21 AJAX(1): 科普 & XHR
Day22 AJAX(2): Fetch
axios 基本使用 & Config
使用 fetch 來進行 Ajax 呼叫
axios小筆記:一些特殊用法