fetch()是 XMLHttpRequest 的升级版,用于在 JavaScript 脚本里面发出 HTTP 请求。浏览器原生提供这个对象
fetch()的功能与 XMLHttpRequest 基本相同,但有三个主要的差异。
在用法上,fetch()接受一个 URL 字符串作为参数,默认向该网址发出 GET 请求,返回一个 Promise 对象。它的基本用法如下。
fetch(url)
.then(...)
.catch(...)
fetch(url)
.then((response) => {
if (response.ok) {
return response.json();
} else {
throw new Error(`HTTP CODE 异常 ${response.status}`);
}
})
.then((data) => {
console.log(data);
})
.catch((err) => {
console.log(err);
});
fetch("./my/test.json")
.then((response) => {
if (response.ok) {
//response.text()
return response.json();
}
})
.then((res) => {
console.log("res", res);
})
.catch((error) => {
console.log("error", error);
});
async function getJSON() {
let url = './my/test.json';
try {
let response = await fetch(url);
return await response.json();
} catch (error) {
console.log('Request Failed', error);
}
}
async function request() {
const response = await fetch("./my/test.json");
console.log("first", response); //
}
request();
basic:普通请求,即同源请求。
cors:跨域请求。
error:网络错误,主要用于 Service Worker。
opaque:如果fetch()请求的type属性设为no-cors,就会返回这个值,详见请求部分。表示发出的是简单的跨域请求,类似
fetch()发出请求以后,有一个很重要的注意点:只有网络错误,或者无法连接时,fetch()才会报错,其他情况都不会报错,而是认为请求成功。即使服务器返回的状态码是 4xx 或 5xx,fetch()也不会报错(即 Promise 不会变为 rejected状态)
async function request() {
const response = await fetch("./my/test.json");
console.log("1", response.ok, response.status); //true 200
if (response.status >= 200 && response.status < 300) {
return await response.text();
} else {
throw new Error(response.statusText);
}
}
request();
Response 对象还有一个Response.headers属性,指向一个 Headers 对象,对应 HTTP 回应的所有标头。
let myHeaders = new Headers(); // Currently empty
myHeaders.append("Content-Type", "text/xml");
console.log("first", myHeaders);
async function request() {
const response = await fetch("./my/test.json", {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
admin: "spj",
},
});
for (let [key, value] of response.headers) {
console.log(`${key} : ${value}`);
}
}
request();
response.text():得到文本字符串。
response.json():得到 JSON 对象。
response.blob():得到二进制 Blob 对象,用于获取二进制文件。
response.formData():得到 FormData 表单对象。
response.arrayBuffer():得到二进制 ArrayBuffer 对象。
const audioCtx = new globalThis.AudioContext();
//返回一个AudioBufferSourceNode对象
const source = audioCtx.createBufferSource();
async function getData() {
const response = await fetch("mp4.mp3");
const buffer = await response.arrayBuffer();
const decodeData = await audioCtx.decodeAudioData(buffer);
source.buffer = decodeData;
source.connect(audioCtx.destination);
source.loop = true;
}
getData();
source.start();
Stream 对象只能读取一次,读取完就没了。这意味着,前一节的五个读取方法,只能使用一个,否则会报错。
async function request() {
const response = await fetch("./my/test.json");
console.log("1", response.json()); //
console.log("2", response.text()()); //Failed to execute 'text' on 'Response': body stream already read
}
request();
const response = await fetch("image.jpeg");
const response1 = response.clone();
const myBlob = await response.blob();
const myBlob1 = await response1.blob();
Response.body属性是 Response 对象暴露出的底层接口,返回一个 ReadableStream 对象,供用户操作。
async function request() {
const response = await fetch("image.jpeg");
const reader = response.body.getReader();
console.log("reader", reader);
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
console.log("value", value, done);
}
}
request();
属性 |
说明 |
method |
请求使用的方法,如 GET、POST、PUT 等 |
body |
请求的 body(请求体) 信息,GET 方法不包含 body 信息 |
headers |
|
mode |
请求的模式,如 cors、no-cors 或者 same-origin
|
credentials |
请求是否携带 Cookie,有三个值:omit、same-origin、include
|
fetch(url, {
// 请求使用的方法,如 `GET`、`POST`、`PUT` 等
method: "post",
// post请求体携带数据,不传递就是 null,可以是键值对、JSON、FormData
body: "username=admin&password=123456",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
// 请求体携带数据
body: "username=icoding&sex=male",
// 跨域时设置,默认值 cors
mode: "cors",
// 跨域时携带 Cookie
credentials: "include",
});
async function request() {
const response = await fetch(url, {
method: "POST",
headers: {
"Content-type": "application/x-www-form-urlencoded; charset=UTF-8",
},
body: "foo=bar&lorem=ipsum",
});
}
request();
const user = { name: 'John', surname: 'Smith' };
const response = await fetch('xxxx/user', {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
body: JSON.stringify(user)
});
const form = document.querySelector('form');
const response = await fetch('xxx/user', {
method: 'POST',
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('xxx/avatars', {
method: 'POST',
body: data
});
let blob = await new Promise(resolve =>
canvasElem.toBlob(resolve, 'image/png')
);
let response = await fetch('xxx/image', {
method: 'POST',
body: blob
});
const response = fetch(url, {
method: "GET/POST",
headers: {
"Content-Type": "text/plain;charset=UTF-8"
},
body: undefined,
referrer: "about:client",
referrerPolicy: "no-referrer-when-downgrade",
mode: "cors",
credentials: "same-origin",
cache: "default",
redirect: "follow",
integrity: "",
keepalive: false,
signal: undefined
});
fetch()请求的底层用的是 Request() 对象的接口,参数完全一样,因此上面的 API 也是Request()的 API,
fetch()请求发送以后,如果中途想要取消,需要使用AbortController对象。
let controller = new AbortController();
let signal = controller.signal;
// fetch(url, {
// signal: controller.signal
// });
// signal.addEventListener('abort',
// () => console.log('abort!')
// );
// controller.abort(); // 取消
// console.log(signal.aborted); // true
let controller = new AbortController();
setTimeout(() => controller.abort(), 1000);
try {
let response = await fetch('/long-operation', {
signal:signal
});
} catch(err) {
if (err.name == 'AbortError') {
console.log('Aborted!');
} else {
throw err;
}
}