Fetch API æä¾äºä¸ä¸ª JavaScript æ¥å£ï¼ç¨äºè®¿é®åæçºµ HTTP 管éçä¸äºå
·ä½é¨åï¼ä¾å¦è¯·æ±åååºãå®è¿æä¾äºä¸ä¸ªå
¨å± fetch()
æ¹æ³ï¼è¯¥æ¹æ³æä¾äºä¸ç§ç®åï¼åççæ¹å¼æ¥è·¨ç½ç»å¼æ¥è·åèµæºã
è¿ç§åè½ä»¥åæ¯ä½¿ç¨ XMLHttpRequest
å®ç°çãFetch æä¾äºä¸ä¸ªæ´çæ³çæ¿ä»£æ¹æ¡ï¼å¯ä»¥å¾å®¹æå°è¢«å
¶ä»ææ¯ä½¿ç¨ï¼ä¾å¦ Service Workers
ãFetch è¿æä¾äºä¸é¨çé»è¾ç©ºé´æ¥å®ä¹å
¶ä»ä¸ HTTP ç¸å
³çæ¦å¿µï¼ä¾å¦ CORS å HTTP çæ©å±ã
请注æï¼fetch
è§èä¸ jQuery.ajax()
ä¸»è¦æä»¥ä¸çä¸åï¼
fetch()
è¿åç Promise ä¸ä¼è¢«æ 记为 rejectï¼å³ä½¿ååºç HTTP ç¶æç æ¯ 404 æ 500ãç¸åï¼å®ä¼å° Promise ç¶ææ 记为 resolveï¼å¦æååºç HTTP ç¶æç ä¸å¨ 200 - 299 çèå´å
ï¼å设置 resolve è¿åå¼ç ok
屿§ä¸º falseï¼ï¼ä»
å½ç½ç»æ
éæ¶æè¯·æ±è¢«é»æ¢æ¶ï¼æä¼æ 记为 rejectãfetch
ä¸ä¼åéè·¨å cookieï¼é¤éä½ ä½¿ç¨äº credentials çåå§åé项ãï¼èª 2018 å¹´ 8 æä»¥åï¼é»è®¤ç credentials æ¿çåæ´ä¸º same-origin
ãFirefox ä¹å¨ 61.0b13 çæ¬ä¸è¿è¡äºä¿®æ¹ï¼ä¸ä¸ªåºæ¬ç fetch 请æ±è®¾ç½®èµ·æ¥å¾ç®åãççä¸é¢ç代ç ï¼
fetch("http://example.com/movies.json")
.then((response) => response.json())
.then((data) => console.log(data));
è¿éæä»¬éè¿ç½ç»è·åä¸ä¸ª JSON æä»¶å¹¶å°å
¶æå°å°æ§å¶å°ãæç®åçç¨æ³æ¯åªæä¾ä¸ä¸ªåæ°ç¨æ¥æææ³ fetch()
å°çèµæºè·¯å¾ï¼ç¶åè¿åä¸ä¸ªå
å«ååºç»æç promiseï¼ä¸ä¸ª Response
对象ï¼ã
å½ç¶å®åªæ¯ä¸ä¸ª HTTP ååºï¼è䏿¯çç JSONã为äºè·å JSON çå
å®¹ï¼æä»¬éè¦ä½¿ç¨ json()
æ¹æ³ï¼è¯¥æ¹æ³è¿åä¸ä¸ªå°ååº body è§£ææ JSON ç promiseï¼ã
夿³¨ï¼ Body è¿æå ¶ä»ç¸ä¼¼çæ¹æ³ï¼ç¨äºè·åå ¶ä»ç±»åçå 容ã
æå¥½ä½¿ç¨ç¬¦åå 容å®å ¨çç¥ (CSP)ç龿¥è䏿¯ä½¿ç¨ç´æ¥æåèµæºå°åçæ¹å¼æ¥è¿è¡ fetch ç请æ±ã
æ¯æç请æ±åæ°fetch()
æ¥å第äºä¸ªå¯éåæ°ï¼ä¸ä¸ªå¯ä»¥æ§å¶ä¸åé
ç½®ç init
对象ï¼
åè fetch()
ï¼æ¥çææå¯éçé
ç½®åæ´å¤æè¿°ã
// Example POST method implementation:
async function postData(url = "", data = {}) {
// Default options are marked with *
const response = await fetch(url, {
method: "POST", // *GET, POST, PUT, DELETE, etc.
mode: "cors", // no-cors, *cors, same-origin
cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
credentials: "same-origin", // include, *same-origin, omit
headers: {
"Content-Type": "application/json",
// 'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: "follow", // manual, *follow, error
referrerPolicy: "no-referrer", // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
body: JSON.stringify(data), // body data type must match "Content-Type" header
});
return response.json(); // parses JSON response into native JavaScript objects
}
postData("https://example.com/answer", { answer: 42 }).then((data) => {
console.log(data); // JSON data parsed by `data.json()` call
});
注æï¼mode: "no-cors"
ä»
å
许使ç¨ä¸ç»æéç HTTP 请æ±å¤´ï¼
Accept
Accept-Language
Content-Language
Content-Type
å
许使ç¨çå¼ä¸ºï¼application/x-www-form-urlencoded
ãmultipart/form-data
æ text/plain
为äºè®©æµè§å¨åéå
å«åæ®ç请æ±ï¼å³ä½¿æ¯è·¨åæºï¼ï¼è¦å° credentials: 'include'
æ·»å å°ä¼ éç» fetch()
æ¹æ³ç init
对象ã
fetch("https://example.com", {
credentials: "include",
});
夿³¨ï¼ å½è¯·æ±ä½¿ç¨ credentials: 'include'
æ¶ï¼ååºç Access-Control-Allow-Origin
ä¸è½ä½¿ç¨éé
符 "*
"ãå¨è¿ç§æ
åµä¸ï¼Access-Control-Allow-Origin
å¿
é¡»æ¯å½å请æ±çæºï¼å¨ä½¿ç¨ CORS Unblock æä»¶çæ
åµä¸è¯·æ±ä»ä¼å¤±è´¥ã
夿³¨ï¼ æ 论æä¹è®¾ç½®ï¼æµè§å¨é½ä¸åºå¨ 颿£è¯·æ± ä¸åéåæ®ãäºè§£æ´å¤ï¼è·¨åèµæºå ±äº« > é带身份åè¯ç请æ±
å¦æä½ åªæ³å¨è¯·æ± URL ä¸è°ç¨èæ¬ä½äºåä¸èµ·æºå¤æ¶åéåæ®ï¼è¯·æ·»å credentials: 'same-origin'
ã
// The calling script is on the origin 'https://example.com'
fetch("https://example.com", {
credentials: "same-origin",
});
è¦æ¹ä¸ºç¡®ä¿æµè§å¨ä¸å¨è¯·æ±ä¸å
å«åæ®ï¼è¯·ä½¿ç¨ credentials: 'omit'
ã
fetch("https://example.com", {
credentials: "omit",
});
ä¸ä¼ JSON æ°æ®
ä½¿ç¨ fetch()
POST JSON æ°æ®
const data = { username: "example" };
fetch("https://example.com/profile", {
method: "POST", // or 'PUT'
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
})
.then((response) => response.json())
.then((data) => {
console.log("Success:", data);
})
.catch((error) => {
console.error("Error:", error);
});
ä¸ä¼ æä»¶
å¯ä»¥éè¿ HTML <input type="file" />
å
ç´ ï¼FormData()
å fetch()
ä¸ä¼ æä»¶ã
const formData = new FormData();
const fileField = document.querySelector('input[type="file"]');
formData.append("username", "abc123");
formData.append("avatar", fileField.files[0]);
fetch("https://example.com/profile/avatar", {
method: "PUT",
body: formData,
})
.then((response) => response.json())
.then((result) => {
console.log("Success:", result);
})
.catch((error) => {
console.error("Error:", error);
});
ä¸ä¼ å¤ä¸ªæä»¶
å¯ä»¥éè¿ HTML <input type="file" multiple />
å
ç´ ï¼FormData()
å fetch()
ä¸ä¼ æä»¶ã
const formData = new FormData();
const photos = document.querySelector('input[type="file"][multiple]');
formData.append("title", "My Vegas Vacation");
for (let i = 0; i < photos.files.length; i++) {
formData.append(`photos_${i}`, photos.files[i]);
}
fetch("https://example.com/posts", {
method: "POST",
body: formData,
})
.then((response) => response.json())
.then((result) => {
console.log("Success:", result);
})
.catch((error) => {
console.error("Error:", error);
});
éè¡å¤çææ¬æä»¶
ä»ååºä¸è¯»åçåå䏿¯æè¡åå²çï¼å¹¶ä¸æ¯ Uint8Array
æ°ç»ç±»åï¼ä¸æ¯å符串类åï¼ãå¦æä½ æ³éè¿ fetch()
è·åä¸ä¸ªææ¬æä»¶å¹¶éè¡å¤çå®ï¼é£éè¦èªè¡å¤çè¿äºå¤ææ
åµã以ä¸ç¤ºä¾å±ç¤ºäºä¸ç§å建è¡è¿ä»£å¨æ¥å¤ççæ¹æ³ï¼ç®åèµ·è§ï¼åè®¾ææ¬æ¯ UTF-8 ç¼ç çï¼ä¸ä¸å¤ç fetch()
çé误ï¼ã
async function* makeTextFileLineIterator(fileURL) {
const utf8Decoder = new TextDecoder("utf-8");
const response = await fetch(fileURL);
const reader = response.body.getReader();
let { value: chunk, done: readerDone } = await reader.read();
chunk = chunk ? utf8Decoder.decode(chunk) : "";
const re = /\n|\r|\r\n/gm;
let startIndex = 0;
let result;
for (;;) {
let result = re.exec(chunk);
if (!result) {
if (readerDone) {
break;
}
let remainder = chunk.substr(startIndex);
({ value: chunk, done: readerDone } = await reader.read());
chunk = remainder + (chunk ? utf8Decoder.decode(chunk) : "");
startIndex = re.lastIndex = 0;
continue;
}
yield chunk.substring(startIndex, result.index);
startIndex = re.lastIndex;
}
if (startIndex < chunk.length) {
// last line didn't end in a newline char
yield chunk.substr(startIndex);
}
}
async function run() {
for await (let line of makeTextFileLineIterator(urlOfFile)) {
processLine(line);
}
}
run();
æ£æµè¯·æ±æ¯å¦æå
妿éå°ç½ç»æ
éææå¡ç«¯ç CORS é
ç½®é误æ¶ï¼fetch()
promise å°ä¼ rejectï¼å¸¦ä¸ä¸ä¸ª TypeError
对象ãè½ç¶è¿ä¸ªæ
åµç»å¸¸æ¯éå°äºæéé®é¢æç±»ä¼¼é®é¢ââæ¯å¦ 404 䏿¯ä¸ä¸ªç½ç»æ
éãæ³è¦ç²¾ç¡®ç夿 fetch()
æ¯å¦æåï¼éè¦å
å« promise resolved çæ
åµï¼æ¤æ¶å夿 Response.ok
æ¯å¦ä¸º trueã类似以ä¸ä»£ç ï¼
fetch("flowers.jpg")
.then((response) => {
if (!response.ok) {
throw new Error("Network response was not OK");
}
return response.blob();
})
.then((myBlob) => {
myImage.src = URL.createObjectURL(myBlob);
})
.catch((error) => {
console.error("There has been a problem with your fetch operation:", error);
});
èªå®ä¹è¯·æ±å¯¹è±¡
é¤äºä¼ ç» fetch()
ä¸ä¸ªèµæºçå°åï¼ä½ è¿å¯ä»¥éè¿ä½¿ç¨ Request()
æé 彿°æ¥å建ä¸ä¸ª request 对象ï¼ç¶ååä½ä¸ºåæ°ä¼ ç» fetch()
ï¼
const myHeaders = new Headers();
const myRequest = new Request("flowers.jpg", {
method: "GET",
headers: myHeaders,
mode: "cors",
cache: "default",
});
fetch(myRequest)
.then((response) => response.blob())
.then((myBlob) => {
myImage.src = URL.createObjectURL(myBlob);
});
Request()
å fetch()
æ¥ååæ ·çåæ°ãä½ çè³å¯ä»¥ä¼ å
¥ä¸ä¸ªå·²åå¨ç request 对象æ¥åé ä¸ä¸ªæ·è´ï¼
const anotherRequest = new Request(myRequest, myInit);
è¿ä¸ªå¾æç¨ï¼å 为 request å response bodies åªè½è¢«ä½¿ç¨ä¸æ¬¡ï¼è¯è
注ï¼è¿éçæææ¯å 为设计æäº stream çæ¹å¼ï¼æä»¥å®ä»¬åªè½è¢«è¯»å䏿¬¡ï¼ãå建ä¸ä¸ªæ·è´å°±å¯ä»¥åæ¬¡ä½¿ç¨ request/response äºï¼å½ç¶ä¹å¯ä»¥ä½¿ç¨ä¸åç init
åæ°ãå建æ·è´å¿
é¡»å¨è¯»å body ä¹åè¿è¡ï¼èä¸è¯»åæ·è´ç body ä¹ä¼å°åå§è¯·æ±ç body æ 记为已读ã
夿³¨ï¼ clone()
æ¹æ³ä¹å¯ä»¥ç¨äºå建ä¸ä¸ªæ·è´ãå®åä¸è¿°æ¹æ³ä¸æ ·ï¼å¦æ request æ response ç body å·²ç»è¢«è¯»åè¿ï¼é£ä¹å°æ§è¡å¤±è´¥ãåºå«å¨äºï¼ clone()
åºç body 被读åä¸ä¼å¯¼è´å body 被æ 记为已读åã
ä½¿ç¨ Headers
çæ¥å£ï¼ä½ å¯ä»¥éè¿ Headers()
æé 彿°æ¥å建ä¸ä¸ªä½ èªå·±ç headers 对象ãä¸ä¸ª headers 对象æ¯ä¸ä¸ªç®åçå¤é®å¼å¯¹ï¼
const content = "Hello World";
const myHeaders = new Headers();
myHeaders.append("Content-Type", "text/plain");
myHeaders.append("Content-Length", content.length.toString());
myHeaders.append("X-Custom-Header", "ProcessThisImmediately");
ä¹å¯ä»¥ä¼ å ¥ä¸ä¸ªå¤ç»´æ°ç»æè 对象åé¢éï¼
const myHeaders = new Headers({
"Content-Type": "text/plain",
"Content-Length": content.length.toString(),
"X-Custom-Header": "ProcessThisImmediately",
});
å®çå 容å¯ä»¥è¢«è·åï¼
console.log(myHeaders.has("Content-Type")); // true
console.log(myHeaders.has("Set-Cookie")); // false
myHeaders.set("Content-Type", "text/html");
myHeaders.append("X-Custom-Header", "AnotherValue");
console.log(myHeaders.get("Content-Length")); // 11
console.log(myHeaders.get("X-Custom-Header")); // ['ProcessThisImmediately', 'AnotherValue']
myHeaders.delete("X-Custom-Header");
console.log(myHeaders.get("X-Custom-Header")); // null
è½ç¶ä¸äºæä½åªè½å¨ ServiceWorkers
ä¸ä½¿ç¨ï¼ä½æ¯å®æä¾äºæ´æ¹ä¾¿çæä½ Headers ç APIã
å¦æä½¿ç¨äºä¸ä¸ªä¸åæ³ç HTTP Header 屿§åï¼é£ä¹ Headers çæ¹æ³éå¸¸é½æåº TypeError å¼å¸¸ã妿ä¸å°å¿åå ¥äºä¸ä¸ªä¸å¯åç屿§ï¼è§ä¸æ¹ï¼ï¼ä¹ä¼æåºä¸ä¸ª TypeError å¼å¸¸ã餿¤ä»¥å¤çæ åµï¼å¤±è´¥äºå¹¶ä¸æåºå¼å¸¸ãä¾å¦ï¼
const myResponse = Response.error();
try {
myResponse.headers.set("Origin", "http://mybank.com");
} catch (e) {
console.log("Cannot pretend to be a bank!");
}
æå¥½å¨å¨ä½¿ç¨ä¹åæ£æ¥å
容类å content-type
æ¯å¦æ£ç¡®ï¼æ¯å¦ï¼
fetch(myRequest)
.then((response) => {
const contentType = response.headers.get("content-type");
if (!contentType || !contentType.includes("application/json")) {
throw new TypeError("Oops, we haven't got JSON!");
}
return response.json();
})
.then((data) => {
/* process your data further */
})
.catch((error) => console.error(error));
Guard
ç±äº Headers å¯ä»¥å¨ request ä¸è¢«åéæè å¨ response ä¸è¢«æ¥æ¶ï¼å¹¶ä¸è§å®äºåªäºåæ°æ¯å¯åçï¼Headers 对象æä¸ä¸ªç¹æ®ç guard 屿§ãè¿ä¸ªå±æ§æ²¡ææ´é²ç» Webï¼ä½æ¯å®å½±åå°åªäºå 容å¯ä»¥å¨ Headers 对象ä¸è¢«æä½ã
å¯è½çå¼å¦ä¸ï¼
none
ï¼é»è®¤çãrequest
ï¼ä» request ä¸è·å¾ç headersï¼Request.headers
ï¼åªè¯»ãrequest-no-cors
ï¼ä»ä¸ååï¼Request.mode
no-cors
ï¼ç request ä¸è·å¾ç headers åªè¯»ãresponse
ï¼ä» response ä¸è·å¾ç headersï¼Response.headers
ï¼åªè¯»ãimmutable
ï¼å¨ ServiceWorkers 䏿叏ç¨çï¼ææç headers é½åªè¯»ã夿³¨ï¼ ä½ ä¸å¯ä»¥æ·»å æè
ä¿®æ¹ä¸ä¸ª guard 屿§æ¯ request
ç Request Header ç Content-Length
屿§ãåæ ·å°ï¼æå
¥ Set-Cookie
屿§å°ä¸ä¸ª response header æ¯ä¸å
许çï¼å æ¤ï¼Service Worker ä¸ï¼ä¸è½ç»åæç Response 设置 cookieã
å¦ä¸æè¿°ï¼Response
å®ä¾æ¯å¨ fetch()
å¤çå® promise ä¹åè¿åçã
ä½ ä¼ç¨å°çæå¸¸è§ç response 屿§æï¼
Response.status
â æ´æ°ï¼é»è®¤å¼ä¸º 200ï¼ä¸º response çç¶æç ãResponse.statusText
â å符串ï¼é»è®¤å¼ä¸º ""ï¼ï¼è¯¥å¼ä¸ HTTP ç¶æç æ¶æ¯å¯¹åºã注æï¼HTTP/2 䏿¯æç¶ææ¶æ¯Response.ok
â å¦ä¸æç¤ºï¼è¯¥å±æ§æ¯æ¥æ£æ¥ response çç¶ææ¯å¦å¨ 200 - 299ï¼å
æ¬ 200 å 299ï¼è¿ä¸ªèå´å
ãè¯¥å±æ§è¿åä¸ä¸ªå¸å°å¼ãå®çå®ä¾ä¹å¯ç¨éè¿ JavaScript æ¥å建ï¼ä½åªæå¨ ServiceWorkers
ä¸ä½¿ç¨ respondWith()
æ¹æ³å¹¶æä¾äºä¸ä¸ªèªå®ä¹ç response æ¥æ¥å request æ¶æçæ£æç¨ï¼
const myBody = new Blob();
addEventListener("fetch", (event) => {
// ServiceWorker intercepting a fetch
event.respondWith(
new Response(myBody, {
headers: { "Content-Type": "text/plain" },
}),
);
});
Response()
æé æ¹æ³æ¥å两个å¯éåæ°ââresponse ç body åä¸ä¸ªåå§å对象ï¼ä¸Request()
ææ¥åç init åæ°ç±»ä¼¼ï¼ã
夿³¨ï¼ éææ¹æ³ error()
åªæ¯è¿åäºé误ç responseã䏿¤ç±»ä¼¼å°ï¼redirect()
åªæ¯è¿åäºä¸ä¸ªå¯ä»¥éå®åè³æ URL ç responseãè¿äºä¹åªä¸ Service Worker æå
³ã
ä¸ç®¡æ¯è¯·æ±è¿æ¯ååºé½è½å¤å å« body 对象ãbody ä¹å¯ä»¥æ¯ä»¥ä¸ä»»æç±»åçå®ä¾ã
ArrayBuffer
ArrayBufferView
(Uint8Array ç)Blob
/FileURLSearchParams
FormData
Body ç±»å®ä¹äºä»¥ä¸æ¹æ³ï¼è¿äºæ¹æ³é½è¢« Request
å Response
æå®ç°ï¼ä»¥è·å body å
容ãè¿äºæ¹æ³é½ä¼è¿åä¸ä¸ªè¢«è§£æåç Promise å¯¹è±¡åæ°æ®ã
Request.arrayBuffer()
/ Response.arrayBuffer()
Request.blob()
/ Response.blob()
Request.formData()
/ Response.formData()
Request.json()
/ Response.json()
Request.text()
/ Response.text()
ç¸æ¯äº XHRï¼è¿äºæ¹æ³è®©éææ¬åæ°æ®çä½¿ç¨æ´å ç®åã
请æ±ä½å¯ä»¥ç±ä¼ å ¥ body åæ°æ¥è¿è¡è®¾ç½®ï¼
const form = new FormData(document.getElementById("login-form"));
fetch("/login", {
method: "POST",
body: form,
});
request å responseï¼å
æ¬ fetch()
æ¹æ³ï¼é½ä¼è¯çèªå¨è®¾ç½® Content-Type
ãå¦ææ²¡æè®¾ç½® Content-Type
å¼ï¼åéç请æ±ä¹ä¼èªå¨è®¾å¼ã
Fetch API çæ¯ææ
åµï¼å¯ä»¥éè¿æ£æµ Headers
, Request
, Response
æ fetch()
æ¯å¦å¨ Window
æ Worker
å䏿¥å¤æãä¾å¦ï¼
if (window.fetch) {
// run my fetch request here
} else {
// do something with XMLHttpRequest?
}
åè§
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4