API ดึงข้อมูล() อยู่ในออบเจ็กต์หน้าต่างและต้องการแทนที่ XHR
XMLHttpRequest ขนาดยาว
fetch()
ช่วยให้คุณสร้างคำขอเครือข่ายที่คล้ายกับ XMLHttpRequest
(XHR) ได้ ความแตกต่างหลักๆ คือ API การดึงข้อมูลจะใช้ Promises ซึ่งทำให้ API ง่ายขึ้นและสะอาดตาขึ้น หลีกเลี่ยงนรกในการติดต่อกลับและต้องจำ API ที่ซับซ้อนของ XMLHttpRequest
API การดึงข้อมูลมีให้ใช้งานในขอบเขต Service Worker ทั่วโลกตั้งแต่ Chrome 40 แต่จะเปิดใช้ในขอบเขตหน้าต่างใน Chrome 42 นอกจากนี้ยังมี polyfill by GitHub ที่แทนการดึงข้อมูลซึ่งคุณนำมาใช้ได้ในปัจจุบันอีกด้วย
หากคุณไม่เคยใช้ Promises มาก่อน โปรดดูข้อมูลเบื้องต้นเกี่ยวกับ JavaScript Promises
คำขอการดึงข้อมูลพื้นฐาน
เรามาเริ่มด้วยการเปรียบเทียบตัวอย่างง่ายๆ ที่นำมาใช้กับ XMLHttpRequest
แล้วเปรียบเทียบกับ fetch
เราแค่ต้องการขอ URL, รับคำตอบและแยกวิเคราะห์เป็น JSON
XMLHttpRequest
XMLHttpRequest
ต้องมีการตั้งค่า Listener 2 รายการเพื่อจัดการกับกรณีความสำเร็จและข้อผิดพลาด รวมถึงการเรียกใช้ open()
และ send()
ตัวอย่างจากเอกสาร MDN
function reqListener() {
var data = JSON.parse(this.responseText);
console.log(data);
}
function reqError(err) {
console.log('Fetch Error :-S', err);
}
var oReq = new XMLHttpRequest();
oReq.onload = reqListener;
oReq.onerror = reqError;
oReq.open('get', './api/some.json', true);
oReq.send();
ดึงข้อมูล
คำขอดึงข้อมูลของเรามีลักษณะดังนี้
fetch('./api/some.json')
.then(
function(response) {
if (response.status !== 200) {
console.log('Looks like there was a problem. Status Code: ' +
response.status);
return;
}
// Examine the text in the response
response.json().then(function(data) {
console.log(data);
});
}
)
.catch(function(err) {
console.log('Fetch Error :-S', err);
});
เราเริ่มต้นด้วยการตรวจสอบว่าสถานะการตอบกลับเป็น 200 ก่อนที่จะแยกวิเคราะห์การตอบกลับเป็น JSON
การตอบกลับของคำขอ fetch()
เป็นออบเจ็กต์สตรีม ซึ่งหมายความว่าเมื่อเราเรียกใช้เมธอด json()
ระบบจะแสดงผล Promise เนื่องจากการอ่านสตรีมเกิดขึ้นแบบไม่พร้อมกัน
ข้อมูลเมตาของการตอบกลับ
ในตัวอย่างก่อนหน้านี้ เราดูที่สถานะของออบเจ็กต์การตอบกลับ รวมถึงวิธีแยกวิเคราะห์การตอบกลับเป็น JSON ข้อมูลเมตาอื่นๆ ที่เราอาจต้องการเข้าถึง เช่น ส่วนหัว แสดงอยู่ด้านล่าง
fetch('users.json').then(function(response) {
console.log(response.headers.get('Content-Type'));
console.log(response.headers.get('Date'));
console.log(response.status);
console.log(response.statusText);
console.log(response.type);
console.log(response.url);
});
ประเภทการตอบสนอง
เมื่อส่งคำขอดึงข้อมูล การตอบกลับจะได้รับ response.type
เป็น response.type
"basic
",
"cors
" หรือ
"opaque
"
types
เหล่านี้จะระบุว่าแหล่งข้อมูลมาจากไหนและสามารถใช้เพื่อให้ทราบว่าคุณควรจัดการออบเจ็กต์คำตอบอย่างไร
เมื่อมีการส่งคำขอสำหรับทรัพยากรจากต้นทางเดียวกัน การตอบกลับจะมีประเภท basic
และไม่มีข้อจำกัดเกี่ยวกับสิ่งที่คุณดูได้จากการตอบกลับ
หากมีการสร้างคำขอสำหรับทรัพยากรในต้นทางอื่นที่แสดงผลส่วนหัวของ COR ประเภทจะเป็น cors
คำตอบ cors
และ basic
แทบจะเหมือนกันทั้งหมด เพียงแต่ว่าการตอบกลับ cors
จำกัดส่วนหัวที่คุณดูได้สำหรับ Cache-Control
, Content-Language
, Content-Type
, Expires
, Last-Modified
และ Pragma
การตอบกลับ opaque
มีไว้สำหรับคำขอทรัพยากรในต้นทางอื่นที่ไม่แสดงผลส่วนหัว CORS เมื่อการตอบสนองไม่ชัดเจน เราจะไม่สามารถอ่านข้อมูลที่ส่งคืนหรือดูสถานะของคำขอได้ ซึ่งหมายความว่าเราไม่สามารถตรวจสอบได้ว่าคำขอดังกล่าวสำเร็จหรือไม่
คุณกำหนดโหมดสำหรับคำขอดึงข้อมูลเพื่อให้มีเพียงคำขอบางรายการเท่านั้นที่จะแก้ไขได้ โหมดที่คุณสามารถตั้งค่ามีดังนี้
same-origin
ประสบความสำเร็จสำหรับคำขอสำหรับเนื้อหาจากต้นทางเดียวกันเท่านั้น ส่วนคำขออื่นๆ ทั้งหมดจะปฏิเสธcors
จะอนุญาตคำขอเนื้อหาในต้นทางเดียวกันและต้นทางอื่นๆ ที่แสดงส่วนหัว COR ที่เหมาะสมcors-with-forced-preflight
จะตรวจสอบล่วงหน้าเสมอก่อนที่จะส่งคำขอจริงno-cors
มีไว้เพื่อส่งคำขอไปยังต้นทางอื่นๆ ที่ไม่มีส่วนหัว CORS และได้ผลลัพธ์เป็นopaque
แต่ตามที่ได้ระบุไว้ การสื่อสารนี้ไม่สามารถทำได้ในขอบเขตรวมทั้งหมดของกรอบเวลาในขณะนี้
หากต้องการกำหนดโหมด ให้เพิ่มออบเจ็กต์ตัวเลือกเป็นพารามิเตอร์ที่ 2 ในคำขอ fetch
และกำหนดโหมดในออบเจ็กต์ดังกล่าว ดังนี้
fetch('http://some-site.com/cors-enabled/some.json', {mode: 'cors'})
.then(function(response) {
return response.text();
})
.then(function(text) {
console.log('Request successful', text);
})
.catch(function(error) {
log('Request failed', error)
});
สัญญาโซ่
ฟีเจอร์ที่ยอดเยี่ยมอย่างหนึ่งของสัญญาคือความสามารถในการผูกไว้ด้วยกัน สำหรับการดึงข้อมูล การดำเนินการนี้จะช่วยให้คุณแชร์ตรรกะข้ามคำขอดึงข้อมูลได้
หากคุณทำงานกับ JSON API คุณจะต้องตรวจสอบสถานะและแยกวิเคราะห์ JSON สำหรับคำตอบแต่ละรายการ คุณลดความซับซ้อนของโค้ดได้โดยกำหนดสถานะและการแยกวิเคราะห์ JSON แยกระหว่างฟังก์ชันต่างๆ ซึ่งจะแสดงผลข้อความ ทำให้คุณกังวลเรื่องการจัดการข้อมูลสุดท้ายและกรณีข้อผิดพลาดเท่านั้น
function status(response) {
if (response.status >= 200 && response.status < 300) {
return Promise.resolve(response)
} else {
return Promise.reject(new Error(response.statusText))
}
}
function json(response) {
return response.json()
}
fetch('users.json')
.then(status)
.then(json)
.then(function(data) {
console.log('Request succeeded with JSON response', data);
}).catch(function(error) {
console.log('Request failed', error);
});
เราจะกำหนดฟังก์ชัน status
ซึ่งจะตรวจสอบ response.status และแสดงผลของ Promise.resolve()
หรือ Promise.reject()
ซึ่งจะแสดงผล Promise ที่แก้ไขแล้วหรือถูกปฏิเสธ นี่คือเมธอดแรกที่เรียกใช้ในเชน fetch()
หากแก้ไขได้ เราจะเรียกใช้เมธอด json()
ซึ่งจะแสดงผลคำสัญญาจากการเรียกใช้ response.json()
อีกครั้ง หลังจากนั้นเรามีออบเจ็กต์ของ JSON ที่แยกวิเคราะห์แล้ว หากการแยกวิเคราะห์ไม่สำเร็จ Promise ถูกปฏิเสธ
และคำสั่ง catch จะทำงาน
ข้อดีอย่างหนึ่งก็คือคุณสามารถแชร์ตรรกะในคำขอการดึงข้อมูลทั้งหมด ซึ่งทำให้ดูแลรักษา อ่าน และทดสอบโค้ดได้ง่ายขึ้น
คำขอ POST
เป็นเรื่องปกติที่เว็บแอปจะต้องการเรียก API ด้วยเมธอด POST และวางพารามิเตอร์บางอย่างในเนื้อหาของคำขอ
วิธีการคือตั้งค่าพารามิเตอร์ method
และ body
ในตัวเลือก fetch()
fetch(url, {
method: 'post',
headers: {
"Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
},
body: 'foo=bar&lorem=ipsum'
})
.then(json)
.then(function (data) {
console.log('Request succeeded with JSON response', data);
})
.catch(function (error) {
console.log('Request failed', error);
});
การส่งข้อมูลเข้าสู่ระบบที่มีคำขอการดึงข้อมูล
หากต้องการส่งคำขอดึงข้อมูลด้วยข้อมูลเข้าสู่ระบบ เช่น คุกกี้ คุณควรตั้งค่า credentials
ของคำขอเป็น "include"
fetch(url, {
credentials: 'include'
})
คำถามที่พบบ่อย
ฉันจะยกเลิกคำขอ fetch() ได้อย่างไร
ขณะนี้คุณยังยกเลิกการดึงข้อมูลไม่ได้ แต่เรากำลังหารือกันใน GitHub H/T @jaffatheจัดเก็บ สำหรับลิงก์นี้
มีโพลีฟิลไหม
GitHub มี Polyfill สำหรับการดึงข้อมูล H/T @Nexii เพื่อแจ้งเรื่องนี้
เหตุใดโปรแกรมทำงานของบริการจึงรองรับ "no-cors" แต่ไม่รองรับหน้าต่าง
สืบเนื่องจากข้อกังวลด้านความปลอดภัย คุณสามารถดูข้อมูลเพิ่มเติมที่นี่