AJAX (Asynchronous JavaScript and XML)的縮寫間單來說是與伺服器進行非同步通訊,可用來自伺服器的資料更新網頁元素,綜合了多項技術的瀏覽器端網頁開發技術。可以增進使用者的操作體驗。
以下介紹幾種使用方法:
JavaScript XHR 透過 XMLHttpRequest(XHR) 物件作為實作。 它能夠在 client 端對 server 端送出 http request,使用的資料格式是 XML(這也變成時代眼淚,現今大多使用 JSON,它的格式像是 JS 中的物件),用 XMLHttpRequest() 取到的結果會是字串,要額外透過 JSON.parse() 轉成 JSON 才可以使用。
Ps.目前較少用,難以閱讀及撰寫,我們大多都會使用框架來處理這段,如 jQuery, Axio…
程式碼大概長這樣:
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 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 物件,需要使用不同資料類型使用對應方法,才能正確取得資料物件。
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 物件,像是圖片就可以做這樣的轉換(指的是圖片檔案本身)。
範例:
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 所送出的資料轉純字串後才能送出。
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 之間。
所以可以多加個判斷
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
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
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
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小筆記:一些特殊用法