---
# System prepended metadata

title: AJAX
tags: [JavaScript]

---

###### tags: `JavaScript`

# AJAX

## 使用流程說明
1. 建立 AJAX 物件
2. 傳送到對方伺服器要資料
3. 伺服器回傳資料到瀏覽器
4. 拿到資料做渲染或是加工處理

### 1. 我們建立一個 XMLHttpRequest() 物件，來用 console 看 xhr 變數裡面存放了哪些東西
```javascript=
var xhr = new XMLHttpRequest();
```

![](https://i.imgur.com/QsoWnFV.gif)

>[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
![](https://i.imgur.com/isdMEwO.gif)

---

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

- 從下圖可知資料已經從伺服器取回來，response 已經有資料
![](https://i.imgur.com/EhQ6Zqu.gif)

---

### 4. 取得資料

- 非同步 true

你會發現用非同步他的資料會是空的，是因為程式碼跑的速度很快，根本來不及等資料回傳你的 console 就會先被打印出來了
![](https://i.imgur.com/0S3n2BC.png)
```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 方法取得資料
![](https://i.imgur.com/K5r8I30.png)
```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 將字串轉成物件傳送到畫面
![](https://i.imgur.com/GKZALWR.png)
```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

使用同步就可以先取得資料了，但是資料量太大可能會等很久造成使用者體驗降低
![](https://i.imgur.com/M4jqMFe.png)
```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 將字串轉成物件傳送到畫面
![](https://i.imgur.com/wY1WHTj.png)
```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 如果沒有開啟會出現下方的錯誤訊息。
 
![](https://i.imgur.com/RPwzfCc.png)

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

![](https://i.imgur.com/We1Ok0d.png)
## 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 方式傳送結果都會一樣，需依照後端工程師的需求來使用
![](https://i.imgur.com/PD4PHuZ.gif)