###### tags: `JavaScript`
# AJAX
## 使用流程說明
1. 建立 AJAX 物件
2. 傳送到對方伺服器要資料
3. 伺服器回傳資料到瀏覽器
4. 拿到資料做渲染或是加工處理
### 1. 我們建立一個 XMLHttpRequest() 物件,來用 console 看 xhr 變數裡面存放了哪些東西
```javascript=
var xhr = new XMLHttpRequest();
```

>[color=red] 重點是 readyState 的數字
readyState 數字 | 代表涵義 |
--- | ---
0 | 你已產生一個 XMLHttpRequest,但還沒有連結你要撈的資料 |
1 | 你用了 open(),但你還沒有把資料送過去 |
2 | 偵測到你有用 send() |
3 | loading 中,有可能資料太大 |
4 | 你撈到資料了,數據已經完全鳩收到 |
---
### 2. open() - 連結遠端外部資料
- xhr.open('格式', '讀取的網址', '同步與非同步')
格式 | 代表涵義 |
--- | ---
get | 讀取資料 |
post | 傳送資料到伺服器 |
同步與非同步 | 代表涵義 |
--- | ---
true | 非同步,不會等資料傳回來,程式碼會繼續往下跑,等到資料回傳才會自動回傳 |
fales | 同步,等資料傳回來,才會讓程式碼會繼續往下跑 |
```javascript=
xhr.open('get','https://hexschool.github.io/ajaxHomework/data.json',true)
```
- 因為使用 open() 所以 readyState 為 1

---
### 3. send() - 傳送資料
```javascript=
// 我們目前只要讀取,所以傳空值(null)給伺服器就好
xhr.send(null)
```
- 因為使用 send() 所以 readyState
會從 2 偵測到 send()
在到 3 讀取資料
完成讀取後回傳資料 readyState 到 4
- 從下圖可知資料已經從伺服器取回來,response 已經有資料

---
### 4. 取得資料
- 非同步 true
你會發現用非同步他的資料會是空的,是因為程式碼跑的速度很快,根本來不及等資料回傳你的 console 就會先被打印出來了

```javascript=
var xhr = new XMLHttpRequest();
xhr.open('get','https://hexschool.github.io/ajaxHomework/data.json',true)
xhr.send(null)
console.log('xhr資料:',xhr.responseText);
```
這時候可以用 xhr 裡面的 onload 方法取得資料

```javascript=
var xhr = new XMLHttpRequest();
xhr.open('get','https://hexschool.github.io/ajaxHomework/data.json',true)
xhr.send(null)
xhr.onload = function(){
console.log('xhr資料:', xhr.responseText);
}
```
再用 JSON.parse 將字串轉成物件傳送到畫面

```javascript=
<span class="text"></span>
<script>
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
}
```
- 同步 fales
使用同步就可以先取得資料了,但是資料量太大可能會等很久造成使用者體驗降低

```javascript=
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 將字串轉成物件傳送到畫面

```javascript=
<span class="text1"></span>
<script>
var xhr = new XMLHttpRequest();
xhr.open('get','https://hexschool.github.io/ajaxHomework/data.json',false)
xhr.send(null)
var str = JSON.parse(xhr.responseText)
document.querySelector('.text1').textContent = str[0].name
</script>
```
## HTTP 狀態碼
狀態碼 | 代表涵義 |
--- | ---
200 | 成功 (OK) |
3XX | 重新導向 (Redirection) |
404 | 找不到檔案或目錄 |
## Cross-Origin Resource Sharing (CORS)
跨來源資源共用(Cross-Origin Resource Sharing (CORS))是一種使用額外 HTTP 標頭令目前瀏覽網站的使用者代理 (en-US)取得存取其他來源(網域)伺服器特定資源權限的機制。當使用者代理請求一個不是目前文件來源——例如來自於不同網域(domain)、通訊協定(protocol)或通訊埠(port)的資源時,會建立一個跨來源 HTTP 請求(cross-origin HTTP request)。
基於安全性考量,程式碼所發出的跨來源 HTTP 請求會受到限制。例如,XMLHttpRequest 及 Fetch 都遵守同源政策(same-origin policy)。這代表網路應用程式所使用的 API 除非使用 CORS 標頭,否則只能請求與應用程式相同網域的 HTTP 資源。
簡單來說就是在同一個網域下 API 可以隨意使用,但是如果在不同網域下要看對方的後端是否有開啟 CORS 如果沒有開啟會出現下方的錯誤訊息。

測試 CORS 網址:http://www.test-cors.org/

## AJAX - 2 種傳送方式
- 傳統傳送方式
- JSON傳送方式
這2種的程式碼差別在
- 表單輸入格式 setRequestHeader 的 application/ 後面不同
- 用 send 傳送 value 方式不同
### AJAX 傳統傳送方式
```javascript=
<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傳送方式
```javascript=
<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 方式傳送結果都會一樣,需依照後端工程師的需求來使用
