本篇為 [FE102] 前端必備:JavaScript 這門課程的學習筆記。如有錯誤歡迎指正。
當我們運用 JavaScript 在網頁進行操作時,主要可分為下列三大面向:
- 介面(Interface):如何改變介面
- 事件(Event):如何監聽事件並做出反應
- 資料(Data):如何和伺服器交換資料
以下主要探討「改變介面」與「事件監聽」的部分。
使用 Node.js 與在瀏覽器上呼叫 API 的差別
Node.js
- 是直接發出 request 到 Server,再直接收到 Server 的 request
- 中間不會受到任何限制
瀏覽器上
- 透過瀏覽器發出 request 到 Server,再透過瀏覽器接收 Server 的 response
- 中間可能會受瀏覽器處理影響,必須按照瀏覽器的規則獲取資料
傳送資料的方式 - 表單 form
<div class="app">
<form method="GET" action="https://google.com">
username:<input name="username"/>
<input type="submit">
</form>
</div>
實際上 request 流程(和 JavaScript 無關):
- 透過
GET
送出 request 給 google 網頁 - 表單的參數會附加在網址上:
https://google.com/?username=123
,因此登入帳密通常會以POST
指令送出 - 瀏覽器接收 response(
301
:轉址),因此會換頁
傳送資料的方式 - AJAX
Ajax,全名是「Asynchronous JavaScript and XML」,重點是 Asynchronous(非同步)。
- JavaScript:使用的程式語言
- XML:Client 與 Server 的資料交換格式。近年由於 JSON 等格式的流行,使用 AJAX 處理的資料已不限於 XML
Ajax 並非單一技術,而是 JavaScript 以「非同步」方式與伺服器交換資料的統稱。使網頁不須換頁,就能即時更新渲染畫面。
Ajax 實現非同步請求(Asynchronous Request)
以 Javascript 程式碼作為範例,可使用 Ajax 這項技術得到 Server 端資料:
// 首先建立了一個 XMLHttpRequest 物件
const request = new XMLHttpRequest()
// 當 load 的時候就會執行 function
request.onload = function () {
// 判斷 request 是否成功
if (request.status >= 200 && request.status < 400) {
console.log(request.responseText)
} else {
console.log('error') // 若失敗.可印出 request.status 得知狀態
}
}
// 當 request 有錯誤就執行 function
request.onerror = function () {
console.log('error')
}
// 要發 request 到哪個地方;true 是非同步,false 是同步
request.open('GET', 'https://reqres.in/api/users', true)
// 發出 request
request.send()
也可改寫成監聽事件語法,會得到相同結果:
request.onload = function () {
// 事件反應...
}
<!-- 可改寫成 -->
request.addEventListener('load', function () {
// 事件反應...
})
使用 AJAX 的好處
- 瀏覽不中斷(即不需要換頁):可提高使用者體驗
- 只需進行局部內容的資料抽換:降低資料量,提高網頁效率
- 用 Ajax 和表單傳送資料的差異,在於如何處理「回傳結果」:
- 表單:是以 html 來傳送資料,當瀏覽器接收到 response 後,頁面就會重新刷新。
- Ajax:當瀏覽器接收 response,會轉傳資料至 JavaScript,進行局部內容的資料抽換,不須換頁就能即時更新頁面。
參考資料:什麼是 Ajax? 搞懂非同步請求 (Asynchronous request)概念
瀏覽器的限制 - 同源政策與跨網域問題
當我們發出 request 給 Google 網頁時,會出現下列訊息,顯示無法取得 response:
這是因為瀏覽器為了安全性而設置的同源政策。一旦脫離瀏覽器,就不會有這些限制。
Same Origin Policy 同源政策
- 兩個網頁具有相同網域、埠號(如果有)以及主機位置
- 具備相同協定:http 和 https 要分開來看
以瀏覽器來說,預設不同來源會擋掉 response,解決方法如 CORS。
CORS 跨來源資源共用
- 全名是 Cross-origin Resource Sharing(CORS)
- 由於同源政策的限制,不同來源要跨網域時,就必須使用這項規則
只要 Server 端在 response header 加上 access-control-allow-origin: *
:
*
:代表所有來源均可存取- 非同源的網域均可以從 Server 存取 response
補充資料:輕鬆理解 Ajax 與跨來源請求
傳送資料的方式 - JSONP(補充)
此方法已經很少使用,僅作為補充。
首先要瞭解下列元素不受同源政策管理:
<img>
:圖片沒有安全性問題<script>
:能夠引入不同源的 JS
JSOPN
- JSON,全名是 JSON with padding,這裡的 padding 是填充的意思
- 是資料格式JSON的一種「使用模式」,和 CORS 同樣能讓網頁從別的網域要資料
透過 JSONP 資料格式,我們可以先藉由 <script src = "要 GET 資料的網域名稱"></script>
讀取網頁的 JS 資訊,再透過指定的 function 進行輸出,就能夠拿到想要的資料。
單向傳送資料的應用(補充)
透過在某個元素裡面塞 src="域名"
,得知使用者是否有打開網頁或其他操作。
- 例如:
<!-- 在圖片塞一個透明的方塊,也不會被使用者察覺 -->
<img width="1" height="1" src="https://user.com/id=134">
一旦使用者打開網頁,將透過 src 傳遞訊息到 Server 端,即可得知使用者進到該頁面。可應用在 email 上,確認使用者是否已經打開信件或廣告,得以進行追蹤。
綜合示範:抓取資料並顯示
以下列程式碼為例:
<head>
<meta charset="utf-8" />
<title>FE102 抓取資料並顯示</title>
<style>
body {
font-size: 38px;
}
.profile {
border: 1px solid #333;
margin-top: 20px;
display: inline-flex;
align-items: center;
}
.profile__name {
margin: 0px 10px;
}
</style>
</head>
<body>
<!-- container -->
<div class="app">
</div>
<script>
// 使用 AJAX 的方法
const request = new XMLHttpRequest()
const container = document.querySelector('.app')
// 當 load 的時候就會執行 function
// 也可寫成:request.addEventListener('load', function() {...})
request.onload = function () {
if (request.status >= 200 && request.status < 400) {
const response = request.responseText
const json = JSON.parse(response)
const users = json.data
for (let i = 0; i < users.length; i++) {
const div = document.createElement('div')
div.classList.add('profile')
div.innerHTML = `
<div class="profile__name">${users[i].first_name} ${users[i].last_name}</div>
<img class="profile__img" src="${users[i].avatar}" />
`
container.appendChild(div)
}
}
}
// request 如果有錯誤就執行
request.onerror = function () {
console.log('error')
}
// 要發 request 到哪個地方
request.open('GET', 'https://reqres.in/api/users', true) //true 是要非同步
// 把 request 傳出去
request.send()
</script>
</body>
也就是說,利用 AJAX 送出一個 HTTP 請求,必須有三個步驟:
1. 建立一個 XMLHttpRequest 物件
- XMLHttpRequest 是一個 JavaScript 準備好的物件,主是要拿來發送 request 與接收 response。
const request = new XMLHttpRequest()
2. 開啟一個 url .open()
request.open(method, url[, async[, user[, password]]])
- 參數分別為:Method、URL、同步/非同步、使用者、密碼
3. 發起一個請求 .send()
request.send()
完成這三個步驟就完成送出一個 HTTP 請求,但我們還需要透過「監聽載入」來取得資料:.onload
,當 load 時就會執行該 function。
「監聽載入」有兩種寫法
目標.onload = function() { … }
目標.addEventListener('load', function() { … })
相關 api 指令
.responseText
:拿到資料.status
:拿到 Http status code 狀態碼
參考資料:
- [第九週]透過瀏覽器交換資料 — 表單、AJAX、XMLHttpRequest
- [第九週]透過瀏覽器交換資料 — 同源政策、CORS、第三種方式 JSONP