Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
etch 是 XMLHttpRequest 的升級版,使用js腳本發出網絡請求,但是與 XMLHttpRequest 不同的是,fetch 方式使用 Promise,相比 XMLHttpRequest 更加簡潔。所以我們告別XMLHttpRequest,引入 fetch 如何使用?
fetch() 是一個全局方法,提供一種簡單,合理的方式跨網絡獲取資源。它的請求是基于 Promise 的,需要詳細學習 Promise ,請點擊《 Promise詳解 》。它是專門為了取代傳統的 xhr 而生的。
1.1、fetch使用語法
fetch(url,options).then((response)=>{
//處理http響應
},(error)=>{
//處理錯誤
})
url :是發送網絡請求的地址。
options:發送請求參數,
1.2、response 對象
fetch 請求成功后,響應 response 對象如圖:
1.3、讀取內容方法
response 對象根據服務器返回的不同類型數據,提供了不同的讀取方法。分別有:
上述 5 個方法,返回的都是 promise 對象,必須等到異步操作結束,才能得到服務器返回的完整數據。
1.4、response.clone()
stream 對象只能讀取一次,讀取完就沒了,這意味著,上邊的五種讀取方法,只能使用一個,否則會報錯。
因此 response 對象提供了 clone() 方法,創建 respons 對象副本,實現多次讀取。如下:將一張圖片,讀取兩次:
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 屬性返回一個 ReadableStream 對象,供用戶操作,可以用來分塊讀取內容,顯示下載的進度就是其中一種應用。
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() 返回一個遍歷器,這個遍歷器 read() 方法每次都會返回一個對象,表示本次讀取的內容塊。
請求方式不同,傳值方式也不同。xhr 會分別處理 get 和 post 數據傳輸,還有請求頭設置,同樣 fetch 也需要分別處理。
2.1、get 方式
只需要在url中加入傳輸數據,options中加入請求方式。如下面代碼所示:
<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('響應',response)
})
}
</script>
2.2、post 方式
使用 post 發送請求時,需要設置請求頭、請求數據等。
將上個實例,改寫成 post 方式提交數據,代碼如下:
fetch(`http://localhost:80/ES6練習題/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('響應',response)
})
如果是提交json數據時,需要把json轉換成字符串。如
body:JSON.stringify(json)
如果提交的是表單數據,使用 formData轉化下,如:
body:new FormData(form)
上傳文件,可以包含在整個表單里一起提交,如:
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
});
上傳二進制數據,將 bolb 或 arrayBuffer 數據放到body屬性里,如:
let blob = await new Promise(resolve =>
canvasElem.toBlob(resolve, 'image/png')
);
let response = await fetch('/article/fetch/post/image', {
method: 'POST',
body: blob
});
3.1、fetch兼容性
fetch原生支持率如圖:
fetch 是相對較新的技術,IE瀏覽器不支持,還有其他低版本瀏覽器也不支持,因此如果使用fetch時,需要考慮瀏覽器兼容問題。
解決辦法:引入 polyfill 完美支持 IE8 以上。
polyfill 的原理就是探測fetch是否支持,如果不支持則用 xhr 實現。支持 fetch 的瀏覽器,響應中文會亂碼,所以使用 fetch-detector 和 fetch-ie8 解決亂碼問題。
3.2、fetch默認不帶cookie
傳遞cookie時,必須在header參數內加上 credentials:'include',才會像 xhr 將當前cookie 帶有請求中。
3.3、異常處理
fetch 不同于 xhr ,xhr 自帶取消、錯誤等方法,所以服務器返回 4xx 或 5xx 時,是不會拋出錯誤的,需要手動處理,通過 response 中的 status 字段來判斷。
avaScript 初學者學完語法,進入實際的網頁編程,一定有人告訴你,要掌握一個叫做 XMLHttpRequest 的東西。
腳本都靠它發出 HTTP 請求,跟服務器通信。所謂的 AJAX 操作就是基于它實現的。要是沒有它,就不會有單頁應用。
這個 XMLHttpRequest 對象,不僅名字怪,用法也非常獨特。
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;
就是因為寫起來麻煩,實際開發中,往往使用它的各種封裝庫,比如早期的 jQuery。
$.get("test.php", function (data) {
$("body")
.append("Name: " + data.name)
.append("Time: " + data.time);
}, "json");
早期的封裝庫都使用回調函數,很不直觀。后來的封裝庫都改用 Promise 的寫法,比如 axios。
axios.get('/user?ID=12345')
.then(function (response) {
// handle success
console.log(response);
})
.catch(function (error) {
// handle error
console.log(error);
})
這樣用起來,確實方便了,但是需要加載外部庫,而它又是一個天天用到的基本需求。所以,瀏覽器廠商最終決定,拋棄 XMLHttpRequest,另起爐灶,重寫一套全新的 API,內置在瀏覽器里面。
這就是 Fetch API,它使用fetch
發出請求,返回的是 Promise 對象。
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 語法,表達起來跟同步操作一模一樣。
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 的優點是寫法簡單,缺點是這個 API 包含的內容非常多,想要完全掌握并不容易。
我一直想寫一篇教程,完整介紹它的各種用法,便于自己使用的時候查找。現在終于寫出來,以后可以告別 XMLHttpRequest 了。
http://www.ruanyifeng.com/blog/2020/12/fetch-tutorial.html
(完)
etch()方法
ECMAscript官方繼續推出了一個基于Promise的請求方法, 更簡單, 更便捷。
就是fetch()方法,這個方法可以替代傳統Ajax請求, 返回Promise的實例。
fetch()函數是ECMAscript提出的新的特性, 它:
能夠發出Ajax請求, 并且請求原理不是xhr, 而是新的原理;
天生可以跨域, 但是需要設置頭, 服務器可以寫腳本識別這個頭部判斷是否應該拒絕它;
fetch()返回Promise對象, 所以可以用then和catch方法, then方法的第一個函數是resolve, 這個resolve的返回值將自動被await等號左邊的變量的接收。
必須寫async和await。
fetch的語法
fetch(url)
.then(res => console.log(res))
.then(res => console.log(res))
.catch(err => console.log(err));
使用場景1
async function main(){
//請求回來的數據都存在body中,作為一種可讀的流返回,要使用json方法轉換
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();
使用場景2
// 請求JSON數據
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了!傳統Ajax已死,fetch永生。
兼容性注意:
babel沒有任何插件可以翻譯fetch為傳統Ajax。
fetch只能用在瀏覽器環境, 不能用在Nodejs環境。
fetch請求的兩種數據格式
html結構:
<div>
<button id="btn1">請求本地文本數據</button>
<button id="btn2">請求網絡json數據</button>
<div id="output"></div>
</div>
JavaScript邏輯:
<script>
document.getElementById('btn1').addEventListener('click', getText);
document.getElementById('btn2').addEventListener('click', getJson);
// 獲取本地純文本數據
function getText(){
fetch("test.txt").then(res => res.text())
.then(data => {console.log(data)})
.catch(err => console.log(err));
}
// 獲取json數據
function getJson(){
fetch("posts.json")
.then(res => res.json())
.then(data => { console.log(data)})
.catch(err => console.log(err));
}
</script>
fetch方法的配置
fetch()方法的第二個參數是配置參數, 可以配置發送POST/PUT/DELETE等請求類型。
fetch('url', [options]);
實踐中, post請求會像下面這樣:
fetch('url', {
method: 'post',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({name:'小明'})
})
.then(data=>{console.log(data)})
.catch(err=>{console.log(err)})
method請求類型參數:
設置請求方式(如POST | PUT | DELETE), fetch默認請求方式為GET。
headers請求頭參數
向服務器說明希望的到什么待遇, 這里主要用到Content-Type
因為一般使用JSON數據格式, 所以設置Content-Type為application/json
body參數設置報文體
要發送給后端的內容, 如果發送JSON數據, 必須調用JSON.stringify()方法。
credentials證書參數
因為默認情況下, fetch不會從服務端發送或接收任何cookies, 所以可以配置以下參數指定發送cookies的情況, 默認值:same-origin, 以下為可選值:
omit: 不發送cookies
same-origin: 在同域情況下發送cookies
include: 同域或跨域都發送cookies
可以理解為:
跨域請求是否提供憑據信息(cookie、HTTP認證及客戶端SSL證明等)
也可以簡單的理解為, 當前請求為跨域類型時是否在請求中協帶cookie。
基于Promise封裝fetch請求庫
用ES6的class類封裝一個函數
app.js
/*
* 基于Promise封裝fetch請求庫
*/
class FetchHttp{
// 封裝get請求
get(url){
return new Promise((resolve,reject)=>{
fetch(url)
.then(data => resolve(data.json()))
.catch(err => reject(err))
})
}
// 封裝post請求
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請求
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請求
delete(url){
return new Promise((resolve, reject)=>{
fetch(url, {
method:"DELETE",
headers:{'Content-type':'application/json'},
})
.then(data => resolve('數據刪除成功!'))
.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; //引入函數
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請求庫app.js
*請認真填寫需求信息,我們會在24小時內與您取得聯系。