整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          前后端數(shù)據(jù)交互(四)-fetch 請(qǐng)求詳解

          etch 是 XMLHttpRequest 的升級(jí)版,使用js腳本發(fā)出網(wǎng)絡(luò)請(qǐng)求,但是與 XMLHttpRequest 不同的是,fetch 方式使用 Promise,相比 XMLHttpRequest 更加簡(jiǎn)潔。所以我們告別XMLHttpRequest,引入 fetch 如何使用?

          一、fetch介紹

          fetch() 是一個(gè)全局方法,提供一種簡(jiǎn)單,合理的方式跨網(wǎng)絡(luò)獲取資源。它的請(qǐng)求是基于 Promise 的,需要詳細(xì)學(xué)習(xí) Promise ,請(qǐng)點(diǎn)擊《 Promise詳解 》。它是專門為了取代傳統(tǒng)的 xhr 而生的。

          1.1、fetch使用語(yǔ)法

          fetch(url,options).then((response)=>{
          //處理http響應(yīng)
          },(error)=>{
          //處理錯(cuò)誤
          })

          url :是發(fā)送網(wǎng)絡(luò)請(qǐng)求的地址。

          options:發(fā)送請(qǐng)求參數(shù),

          • body - http請(qǐng)求參數(shù)
          • mode - 指定請(qǐng)求模式。默認(rèn)值為cros:允許跨域;same-origin:只允許同源請(qǐng)求;no-cros:只限于get、post和head,并且只能使用有限的幾個(gè)簡(jiǎn)單標(biāo)頭。
          • cache - 用戶指定緩存。
          • method - 請(qǐng)求方法,默認(rèn)GET
          • signal - 用于取消 fetch
          • headers - http請(qǐng)求頭設(shè)置
          • keepalive - 用于頁(yè)面卸載時(shí),告訴瀏覽器在后臺(tái)保持連接,繼續(xù)發(fā)送數(shù)據(jù)。
          • credentials - cookie設(shè)置,默認(rèn)omit,忽略不帶cookie,same-origin同源請(qǐng)求帶cookie,inclue無(wú)論跨域還是同源都會(huì)帶cookie。

          1.2、response 對(duì)象

          fetch 請(qǐng)求成功后,響應(yīng) response 對(duì)象如圖:

          • status - http狀態(tài)碼,范圍在100-599之間
          • statusText - 服務(wù)器返回狀態(tài)文字描述
          • ok - 返回布爾值,如果狀態(tài)碼2開頭的,則true,反之false
          • headers - 響應(yīng)頭
          • body - 響應(yīng)體。響應(yīng)體內(nèi)的數(shù)據(jù),根據(jù)類型各自處理。
          • type - 返回請(qǐng)求類型。
          • redirected - 返回布爾值,表示是否發(fā)生過跳轉(zhuǎn)。

          1.3、讀取內(nèi)容方法

          response 對(duì)象根據(jù)服務(wù)器返回的不同類型數(shù)據(jù),提供了不同的讀取方法。分別有:

          1. response.text() -- 得到文本字符串
          2. response.json() - 得到 json 對(duì)象
          3. response.blob() - 得到二進(jìn)制 blob 對(duì)象
          4. response.formData() - 得到 fromData 表單對(duì)象
          5. response.arrayBuffer() - 得到二進(jìn)制 arrayBuffer 對(duì)象

          上述 5 個(gè)方法,返回的都是 promise 對(duì)象,必須等到異步操作結(jié)束,才能得到服務(wù)器返回的完整數(shù)據(jù)。

          1.4、response.clone()

          stream 對(duì)象只能讀取一次,讀取完就沒了,這意味著,上邊的五種讀取方法,只能使用一個(gè),否則會(huì)報(bào)錯(cuò)。

          因此 response 對(duì)象提供了 clone() 方法,創(chuàng)建 respons 對(duì)象副本,實(shí)現(xiàn)多次讀取。如下:將一張圖片,讀取兩次:

          const response1 = await fetch('flowers.jpg');
          const response2 = response1.clone();
          
          const myBlob1 = await response1.blob();
          const myBlob2 = await response2.blob();
          
          image1.src = URL.createObjectURL(myBlob1);
          image2.src = URL.createObjectURL(myBlob2);

          1.4、response.body()

          body 屬性返回一個(gè) ReadableStream 對(duì)象,供用戶操作,可以用來(lái)分塊讀取內(nèi)容,顯示下載的進(jìn)度就是其中一種應(yīng)用。

          const response = await fetch('flower.jpg');
          const reader = response.body.getReader();
          while(true) {
            const {done, value} = await reader.read();
            if (done) {
              break;
            }
            console.log(`Received ${value.length} bytes`)
          }

          response.body.getReader() 返回一個(gè)遍歷器,這個(gè)遍歷器 read() 方法每次都會(huì)返回一個(gè)對(duì)象,表示本次讀取的內(nèi)容塊。

          二、請(qǐng)求時(shí) POST 和 GET 分別處理

          請(qǐng)求方式不同,傳值方式也不同。xhr 會(huì)分別處理 get 和 post 數(shù)據(jù)傳輸,還有請(qǐng)求頭設(shè)置,同樣 fetch 也需要分別處理。

          2.1、get 方式

          只需要在url中加入傳輸數(shù)據(jù),options中加入請(qǐng)求方式。如下面代碼所示:

          <input type="text" id="user"><br>
          <input type="password" id="pas"><br>
          <button onclick="login()">提交</button>
          <script>
           function login(){
            fetch(`http://localhost:80/fetch.html?user=${user.value}&pas=${pas.value}`,{
             method:'GET'
            }).then(response=>{
             console.log('響應(yīng)',response)
            })
           }
          </script>

          2.2、post 方式

          使用 post 發(fā)送請(qǐng)求時(shí),需要設(shè)置請(qǐng)求頭、請(qǐng)求數(shù)據(jù)等。

          將上個(gè)實(shí)例,改寫成 post 方式提交數(shù)據(jù),代碼如下:

          fetch(`http://localhost:80/ES6練習(xí)題/53fetch.html`,{
           method:'POST',
           headers:{
            'Content-Type':'application/x-www-form-urlencoded;charset=UTF-8'
           },
           body:`user=${user.value}&pas=${pas.value}`
           }).then(response=>{
            console.log('響應(yīng)',response)
          })

          如果是提交json數(shù)據(jù)時(shí),需要把json轉(zhuǎn)換成字符串。如

          body:JSON.stringify(json)

          如果提交的是表單數(shù)據(jù),使用 formData轉(zhuǎn)化下,如:

          body:new FormData(form)

          上傳文件,可以包含在整個(gè)表單里一起提交,如:

          const input = document.querySelector('input[type="file"]');
          
          const data = new FormData();
          data.append('file', input.files[0]);
          data.append('user', 'foo');
          
          fetch('/avatars', {
            method: 'POST',
            body: data
          });

          上傳二進(jìn)制數(shù)據(jù),將 bolb 或 arrayBuffer 數(shù)據(jù)放到body屬性里,如:

          let blob = await new Promise(resolve =>   
            canvasElem.toBlob(resolve,  'image/png')
          );
          
          let response = await fetch('/article/fetch/post/image', {
            method:  'POST',
            body: blob
          });

          三、fetch 常見坑

          3.1、fetch兼容性

          fetch原生支持率如圖:

          fetch 是相對(duì)較新的技術(shù),IE瀏覽器不支持,還有其他低版本瀏覽器也不支持,因此如果使用fetch時(shí),需要考慮瀏覽器兼容問題。

          解決辦法:引入 polyfill 完美支持 IE8 以上。

          • 由于 IE8 是 ES3,需要引入 ES5 的 polyfill: es5-shim, es5-sham
          • 引入 Promise 的 polyfill:es6-promise
          • 引入 fetch 探測(cè)庫(kù):fetch-detector
          • 引入 fetch 的 polyfill: fetch-ie8
          • 可選:如果你還使用了 jsonp,引入 fetch-jsonp
          • 可選:開啟 Babel 的 runtime 模式,現(xiàn)在就使用 async/await

          polyfill 的原理就是探測(cè)fetch是否支持,如果不支持則用 xhr 實(shí)現(xiàn)。支持 fetch 的瀏覽器,響應(yīng)中文會(huì)亂碼,所以使用 fetch-detector 和 fetch-ie8 解決亂碼問題。

          3.2、fetch默認(rèn)不帶cookie

          傳遞cookie時(shí),必須在header參數(shù)內(nèi)加上 credentials:'include',才會(huì)像 xhr 將當(dāng)前cookie 帶有請(qǐng)求中。

          3.3、異常處理

          fetch 不同于 xhr ,xhr 自帶取消、錯(cuò)誤等方法,所以服務(wù)器返回 4xx 或 5xx 時(shí),是不會(huì)拋出錯(cuò)誤的,需要手動(dòng)處理,通過 response 中的 status 字段來(lái)判斷。

          avaScript 初學(xué)者學(xué)完語(yǔ)法,進(jìn)入實(shí)際的網(wǎng)頁(yè)編程,一定有人告訴你,要掌握一個(gè)叫做 XMLHttpRequest 的東西。

          腳本都靠它發(fā)出 HTTP 請(qǐng)求,跟服務(wù)器通信。所謂的 AJAX 操作就是基于它實(shí)現(xiàn)的。要是沒有它,就不會(huì)有單頁(yè)應(yīng)用。

          這個(gè) XMLHttpRequest 對(duì)象,不僅名字怪,用法也非常獨(dú)特。

          let xhr = new XMLHttpRequest;xhr.open('GET', url)xhr.onload = function  { if (this.status === 200) { let data = JSON.parse(this.responseText); console.log(data); }};xhr.onerror = function (err) { console.log('Error Occurred :', err);}xhr.send;

          就是因?yàn)閷懫饋?lái)麻煩,實(shí)際開發(fā)中,往往使用它的各種封裝庫(kù),比如早期的 jQuery。

          $.get("test.php", function (data) { $("body") .append("Name: " + data.name)  .append("Time: " + data.time);}, "json");

          早期的封裝庫(kù)都使用回調(diào)函數(shù),很不直觀。后來(lái)的封裝庫(kù)都改用 Promise 的寫法,比如 axios。

          axios.get('/user?ID=12345') .then(function (response) { // handle success console.log(response); }) .catch(function (error) { // handle error console.log(error); })

          這樣用起來(lái),確實(shí)方便了,但是需要加載外部庫(kù),而它又是一個(gè)天天用到的基本需求。所以,瀏覽器廠商最終決定,拋棄 XMLHttpRequest,另起爐灶,重寫一套全新的 API,內(nèi)置在瀏覽器里面。

          這就是 Fetch API,它使用fetch發(fā)出請(qǐng)求,返回的是 Promise 對(duì)象。

          fetch('https://api.github.com/users/ruanyf') .then(response => response.json) .then(json => console.log(json)) .catch(err => console.log('Request Failed', err)); 

          Promise 可以使用 await 語(yǔ)法,表達(dá)起來(lái)跟同步操作一模一樣。

          async function getJSON { let url = 'https://api.github.com/users/ruanyf'; try { let response = await fetch(url); return await response.json; } catch (error) { console.log('Request Failed', error); }}

          Fetch API 的優(yōu)點(diǎn)是寫法簡(jiǎn)單,缺點(diǎn)是這個(gè) API 包含的內(nèi)容非常多,想要完全掌握并不容易。

          我一直想寫一篇教程,完整介紹它的各種用法,便于自己使用的時(shí)候查找。現(xiàn)在終于寫出來(lái),以后可以告別 XMLHttpRequest 了。

          http://www.ruanyifeng.com/blog/2020/12/fetch-tutorial.html

          (完)

          etch()方法

          ECMAscript官方繼續(xù)推出了一個(gè)基于Promise的請(qǐng)求方法, 更簡(jiǎn)單, 更便捷。

          就是fetch()方法,這個(gè)方法可以替代傳統(tǒng)Ajax請(qǐng)求, 返回Promise的實(shí)例。

          fetch()函數(shù)是ECMAscript提出的新的特性, 它:

          能夠發(fā)出Ajax請(qǐng)求, 并且請(qǐng)求原理不是xhr, 而是新的原理;

          天生可以跨域, 但是需要設(shè)置頭, 服務(wù)器可以寫腳本識(shí)別這個(gè)頭部判斷是否應(yīng)該拒絕它;

          fetch()返回Promise對(duì)象, 所以可以用then和catch方法, then方法的第一個(gè)函數(shù)是resolve, 這個(gè)resolve的返回值將自動(dòng)被await等號(hào)左邊的變量的接收。

          必須寫async和await。

          fetch的語(yǔ)法

          fetch(url)
          .then(res => console.log(res))
          .then(res => console.log(res))

          .catch(err => console.log(err));

          使用場(chǎng)景1

          async function main(){
          //請(qǐng)求回來(lái)的數(shù)據(jù)都存在body中,作為一種可讀的流返回,要使用json方法轉(zhuǎn)換
          var data1 = await fetch("data/1.json").then(data=>data.json());
          var data2 = await fetch("data/2.json").then(data=>data.json());
          var data3 = await fetch("data/3.json").then(data=>data.json());
          console.log(data1)
          console.log(data2)
          console.log(data3)
          };
          main();

          使用場(chǎng)景2

          // 請(qǐng)求JSON數(shù)據(jù)
          async function getUsers(){
          const res = await fetch("https://www.xxx.com");
          const data = await res.json();
          return data;
          }
          getUsers()
          .then((users) => console.log(users))
          .catch((err) => console.log(err))

          可以不用jQuery了!傳統(tǒng)Ajax已死,fetch永生。

          兼容性注意:

          babel沒有任何插件可以翻譯fetch為傳統(tǒng)Ajax。

          fetch只能用在瀏覽器環(huán)境, 不能用在Nodejs環(huán)境。

          fetch請(qǐng)求的兩種數(shù)據(jù)格式

          html結(jié)構(gòu):

          <div>
          <button id="btn1">請(qǐng)求本地文本數(shù)據(jù)</button>
          <button id="btn2">請(qǐng)求網(wǎng)絡(luò)json數(shù)據(jù)</button>
          <div id="output"></div>
          </div>

          JavaScript邏輯:

          <script>

          document.getElementById('btn1').addEventListener('click', getText);
          document.getElementById('btn2').addEventListener('click', getJson);
          // 獲取本地純文本數(shù)據(jù)
          function getText(){
          fetch("test.txt").then(res => res.text())
          .then(data => {console.log(data)})
          .catch(err => console.log(err));
          }
          // 獲取json數(shù)據(jù)
          function getJson(){
          fetch("posts.json")
          .then(res => res.json())
          .then(data => { console.log(data)})
          .catch(err => console.log(err));
          }
          </script>

          fetch方法的配置

          fetch()方法的第二個(gè)參數(shù)是配置參數(shù), 可以配置發(fā)送POST/PUT/DELETE等請(qǐng)求類型。

          fetch('url', [options]);

          實(shí)踐中, post請(qǐng)求會(huì)像下面這樣:

          fetch('url', {
          method: 'post',
          headers: {
          'Content-Type': 'application/json'
          },
          body: JSON.stringify({name:'小明'})
          })
          .then(data=>{console.log(data)})
          .catch(err=>{console.log(err)})

          method請(qǐng)求類型參數(shù):

          設(shè)置請(qǐng)求方式(如POST | PUT | DELETE), fetch默認(rèn)請(qǐng)求方式為GET。

          headers請(qǐng)求頭參數(shù)

          向服務(wù)器說明希望的到什么待遇, 這里主要用到Content-Type

          因?yàn)橐话闶褂肑SON數(shù)據(jù)格式, 所以設(shè)置Content-Type為application/json

          body參數(shù)設(shè)置報(bào)文體

          要發(fā)送給后端的內(nèi)容, 如果發(fā)送JSON數(shù)據(jù), 必須調(diào)用JSON.stringify()方法。

          credentials證書參數(shù)

          因?yàn)槟J(rèn)情況下, fetch不會(huì)從服務(wù)端發(fā)送或接收任何cookies, 所以可以配置以下參數(shù)指定發(fā)送cookies的情況, 默認(rèn)值:same-origin, 以下為可選值:

          omit: 不發(fā)送cookies

          same-origin: 在同域情況下發(fā)送cookies

          include: 同域或跨域都發(fā)送cookies

          可以理解為:

          跨域請(qǐng)求是否提供憑據(jù)信息(cookie、HTTP認(rèn)證及客戶端SSL證明等)

          也可以簡(jiǎn)單的理解為, 當(dāng)前請(qǐng)求為跨域類型時(shí)是否在請(qǐng)求中協(xié)帶cookie。

          基于Promise封裝fetch請(qǐng)求庫(kù)

          用ES6的class類封裝一個(gè)函數(shù)

          app.js

          /*
          * 基于Promise封裝fetch請(qǐng)求庫(kù)
          */
          class FetchHttp{
          // 封裝get請(qǐng)求
          get(url){
          return new Promise((resolve,reject)=>{
          fetch(url)
          .then(data => resolve(data.json()))
          .catch(err => reject(err))
          })
          }
          // 封裝post請(qǐng)求
          post(url, data){
          return new Promise((resolve, reject)=>{
          fetch(url, {
          method:"POST",
          headers:{'Content-type':'application/json'},
          body:JSON.stringify(data)
          })
          .then(data => resolve(data.json()))
          .catch(err => reject(err))
          })
          }
          // 封裝put請(qǐng)求
          put(url, data){
          return new Promise((resolve, reject)=>{
          fetch(url, {
          method:"PUT",
          headers:{'Content-type':'application/json'},
          body:JSON.stringify(data)
          })
          .then(data => resolve(data.json()))
          .catch(err => reject(err))
          })
          }
          // 封裝delete請(qǐng)求
          delete(url){
          return new Promise((resolve, reject)=>{
          fetch(url, {
          method:"DELETE",
          headers:{'Content-type':'application/json'},
          })
          .then(data => resolve('數(shù)據(jù)刪除成功!'))
          .catch(err => reject(err))
          })
          }
          }
          <!DOCTYPE html>
          <html lang="en">
          <head>
          <meta charset="UTF-8" />
          <title>Document</title>
          </head>
          <body>
          </body>
          <script src="js/app.js"></script>
          <script>
          const http = new FetchHttp; //引入函數(shù)
          const data = {
          name:"小明",
          sex:"男",
          age:29
          }
          http.delete("https://www.xxx.com")
          .then(data=>{console.log(data)})
          .catch(err=>{console.log(err)})
          </script>
          </html>


          基于async封裝fetch請(qǐng)求庫(kù)app.js


          主站蜘蛛池模板: 精品人妻一区二区三区毛片| 精品国产一区二区三区色欲| 亚洲日韩AV一区二区三区四区| 国产一区高清视频| 一夲道无码人妻精品一区二区| 日韩美一区二区三区| 亚洲高清一区二区三区| 一区二区三区午夜视频| 国产午夜精品一区理论片| 一区二区三区在线观看免费| 欧洲精品免费一区二区三区| 国产电影一区二区| 91亚洲一区二区在线观看不卡| 国产精品女同一区二区| 香蕉视频一区二区| 激情综合一区二区三区| 精品福利一区二区三| 国模吧一区二区三区| 亚洲国产综合精品中文第一区| 美女一区二区三区| 人妻无码一区二区不卡无码av| 99精品国产一区二区三区不卡| 人妻少妇精品视频一区二区三区| 亚洲一区中文字幕久久| 亚洲视频免费一区| 精品无人乱码一区二区三区| 亚洲AV无码一区二区乱子仑| 欧亚精品一区三区免费| 国产日韩精品一区二区三区| 精品一区二区三区四区电影| 一区二区三区中文| 日韩精品成人一区二区三区| 日韩高清国产一区在线| 国产成人久久精品区一区二区 | 无码丰满熟妇一区二区| 精品久久久久久中文字幕一区| 白丝爆浆18禁一区二区三区| 日韩精品无码Av一区二区| 中文字幕一区二区三区精华液 | 国产精品免费综合一区视频| 午夜精品一区二区三区在线视|