[toc]
### Fetch Api概述
Fetch Api并非ES6語言標準范圍內的內容,其屬于HTML5新增的 Web Api,但由于其采用Promise方式,更利于異步代碼的書寫。因此將該方法放在異步處理后面進行學習。
**XMLHttpRequest的問題**
1. 所有的功能全部集中在同一個對象上,容易書寫出混亂不易維護的代碼
2. 采用傳統的事件驅動模式,無法適配新的 Promise Api
**Fetch Api 的特點**
1. Fetch Api并非取代 AJAX,而是對 AJAX 傳統 API 的改進
2. 精細的功能分割:頭部信息、請求信息、響應信息等均分布到不同的對象,更利于處理各種復雜的 AJAX 場景
3. 使用 Promise Api,更利于異步代碼的書寫
4.
### Fetch Api的用法
#### 基本使用
> 請求測試地址:http://101.120.82.37:5200/testapi/local (僅為書寫,該地址不可用)
使用 ```fetch``` 函數即可立即向服務器發送網絡請求
```js
// fetch的標準用法
const url = "http://101.120.82.37:5200/testapi/local";
const resp = await fetch(url) //當服務器有響應,獲得其返回結果的Promise對象
const result = await resp.json(); //將服務器返回的Promise對象中的返回結果以json格式返回
console.log(result)
```
#### 參數
該函數有兩個參數:
1. 必填,字符串,請求地址
2. 選填,對象,請求配置
**請求配置對象**
- method:字符串,請求方法,默認值GET
- headers:對象,請求頭信息
- body: 請求體的內容,必須匹配請求頭中的 Content-Type
- mode:字符串,請求模式
- cors:默認值,配置為該值,會在請求頭中加入 origin 和 referer
- no-cors:配置為該值,不會在請求頭中加入 origin 和 referer,跨域的時候可能會出現問題
- same-origin:指示請求必須在同一個域中發生,如果請求其他域,則會報錯
- credentials: 如何攜帶憑據(cookie)
- omit:默認值,不攜帶cookie
- same-origin:請求同源地址時攜帶cookie
- include:請求任何地址都攜帶cookie
- cache:配置緩存模式
- default: 表示fetch請求之前將檢查下http的緩存.
- no-store: 表示fetch請求將完全忽略http緩存的存在. 這意味著請求之前將不再檢查下http的緩存, 拿到響應后, 它也不會更新http緩存.
- no-cache: 如果存在緩存, 那么fetch將發送一個條件查詢request和一個正常的request, 拿到響應后, 它會更新http緩存.
- reload: 表示fetch請求之前將忽略http緩存的存在, 但是請求拿到響應后, 它將主動更新http緩存.
- force-cache: 表示fetch請求不顧一切的依賴緩存, 即使緩存過期了, 它依然從緩存中讀取. 除非沒有任何緩存, 那么它將發送一個正常的request.
- only-if-cached: 表示fetch請求不顧一切的依賴緩存, 即使緩存過期了, 它依然從緩存中讀取. 如果沒有緩存, 它將拋出網絡錯誤(該設置只在mode為”same-origin”時有效).
#### 返回值
fetch 函數返回一個 Promise 對象
- 當收到服務器的返回結果后,Promise 進入resolved狀態,狀態數據為 Response 對象
- 當網絡發生錯誤(或其他導致無法完成交互的錯誤)時,Promise 進入 rejected 狀態,狀態數據為錯誤信息
### Request 對象
除了使用基本的fetch添加參數的方法,還可以通過創建一個Request對象做為參數傳給fetch來完成請求(實際上,fetch的內部也會把傳遞進來的參數創建成一個Request對象)
```js
new Request(url地址, 配置)
```
```js
//定義一個Request對象
function getRequest(){
let url = 'http://101.120.82.37:5200/testapi/local'
let req = new Request(url, {});
return req
}
//發送fetch請求的時候可以這樣寫
let resp = fetch(getRequest()); //得到請求返回的Promise對象
let result = resp.json(); //用json格式獲得請求返回的結果
console.log(result);
```
**注意**
盡量保證每次請求都是一個新的Request對象。如果定義好了一個Request對象,重新發送請求的時候Request對象中的數據并沒有改變,但又想得到一個新的Request對象,可以使用Request對象的clone方法。
```js
function getRequest(){
let url = 'http://101.120.82.37:5200/testapi/local'
let req = new Request(url, {});
return req.clone()
}
//這樣每次就會獲得一個新的Request對象
```
### Response 對象
Response對象是fetch發送請求后,Promise對象返回resolve結果時的對象。該對象通常為返回時自動創建。
該對象的基本屬性如下:
- ok:boolean,當響應消息碼在200~299之間時為true,其他為false
- status:number,響應的狀態碼
- text():用于處理文本格式的 Ajax 響應。它從響應中獲取文本流,將其讀完,然后返回一個被解決為 string 對象的 Promise。
- blob():用于處理二進制文件格式(比如圖片或者電子表格)的 Ajax 響應。它讀取文件的原始數據,一旦讀取完整個文件,就返回一個被解決為 blob 對象的 Promise。
- json():用于處理 JSON 格式的 Ajax 的響應。它將 JSON 數據流轉換為一個被解決為 JavaScript 對象的promise。
- redirect():可以用于重定向到另一個 URL。它會創建一個新的 Promise,以解決來自重定向的 URL 的響應。
Response對象也可以手動創建,用于模擬服務器返回的數據。平時很少使用
```js
const resp = new Response(`[
{'id': 0, 'name': '小張'},
{'id': 1, 'name': '小劉'},
]`, //第一個參數用來寫json格式的數據體,可以使用模版字符來創建
{
ok: true,
status: 200,
} //第二個參數用來設置Response對象中的相關屬性
)
```
### Headers 對象
在Request和Response對象內部,會將傳遞的請求頭對象,轉換為一個Headers對象
開發過程中,通常請求頭中的數據基本不變,可以聲明一個Headers對象,省去每次發送請求時都要重復填寫請求頭內容。
```js
const header = new Headers({
title: '標題',
content: '內容'
})
//這樣就創建了一個請求頭對象,結合上面的Request對象,發送請求的時候參數可以直接填寫兩個對象名即可
const resp = fetch(getRequest(), header)
//這種方式可以更加的節省代碼的重復書寫
```
獲取返回數據中的Headers對象:
```js
const result = resp.headers
```
Headers對象中的方法:
- has(key):檢查請求頭中是否存在指定的key值
- get(key): 得到請求頭中對應的key值
- set(key, value):修改對應的鍵值對
- append(key, value):添加對應的鍵值對
- keys(): 得到所有的請求頭鍵的集合
- values(): 得到所有的請求頭中的值的集合
- entries(): 得到所有請求頭中的鍵值對的集合
### 文件上傳
流程:
1. 客戶端將文件數據發送給服務器
2. 服務器保存上傳的文件數據到服務器端
3. 服務器響應給客戶端一個文件訪問地址
> 測試地址:http://101.120.82.37:5200/testapi/local
> 鍵的名稱(表單域名稱):imagefile
請求方法:POST
請求的表單格式:multipart/form-data
請求體中必須包含一個鍵值對,鍵的名稱是服務器要求的名稱,值是文件數據
> HTML5中,JS仍然無法隨意的獲取文件數據,但是可以獲取到input元素中,被用戶選中的文件數據
> 可以利用HTML5提供的FormData構造函數來創建請求體