javascript高级编程系列 - 使用fetch发送http请求
fetch 采用模块化设计,api分散在多个对象上(Response对象,Request对象,Header对象),
fetch通过数据流(stream对象)处理数据可以分块读取,有利于提高网站性能。
发送GET请求
fetch 函数只传递一个url,默认以get方法发送请求。
- promise
fetch(url)
.then(response => response.json())
.then(json => console.log(json))
.catch(err => console.log('Request Failed', err));
- async & await
async function getJSON() {
const url = 'http://example.com';
try {
const response = await fetch(url);
return await response.json();
} catch (error) {
console.log('Request Failed', error);
}
}
发送POST请求
- 发送表单数据
async function sendPost() {
const url = 'http://example.com';
try {
const response = await fetch(url, {
method: 'POST',
headers: {
"Content-type": "application/x-www-form-urlencoded; charset=UTF-8",
},
body: 'foo=bar&lorem=ipsum',
});
const json = await response.json();
console.log(json);
} catch(error) {
console.log('Request Failed', error);
}
}
- 发送json数据
async function sendJson() {
const url = 'http://example.com';
const user = { name: 'John', surname: 'Smith' };
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
body: JSON.stringify(user)
});
const json = await response.json();
console.log(json);
} catch(error) {
console.log('Request Failed', error);
}
}
- 提交表单数据
const form = document.querySelector('form');
const response = await fetch('/users', {
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('/avatars', {
method: 'POST',
body: data
});
- 上传二进制数据
let blob = await new Promise(resolve =>
canvasElem.toBlob(resolve, 'image/png')
);
let response = await fetch('/article/fetch/post/image', {
method: 'POST',
body: blob
});
判断请求是否成功
- response.ok
Response.ok属性返回一个布尔值,表示请求是否成功,true对应 HTTP 请求的状态码 200 到 299,false对应其他的状态码。
async function fetchText() {
let response = await fetch('/readme.txt');
if (response.ok) {
return await response.text();
} else {
throw new Error(response.statusText);
}
}
- response.status
Response.status属性返回一个数字,表示 HTTP 回应的状态码(例如200,表示成功请求)。
async function fetchText() {
let response = await fetch('/readme.txt');
if (response.status >= 200 && response.status < 300) {
return await response.text();
} else {
throw new Error(response.statusText);
}
}
读取返回内容的方法
- response.text():得到文本字符串。
const response = await fetch('/users.html');
const body = await response.text();
document.body.innerHTML = body
- response.json():得到 JSON 对象。
- response.blob():得到二进制 Blob 对象。
const response = await fetch('flower.jpg');
const myBlob = await response.blob();
const objectURL = URL.createObjectURL(myBlob);
const myImage = document.querySelector('img');
myImage.src = objectURL;
- response.formData():得到 FormData 表单对象。
- response.arrayBuffer():得到二进制 ArrayBuffer 对象。
- response.clone(): 创建response流对象的副本, 用于多次读取。
- response.body.getReader(): 返回一个遍历器,这个遍历器的read()方法每次返回一个对象,表示本次读取的内容块。
const response = await fetch('flower.jpg');
const reader = response.body.getReader();
while(true) {
/* 这个对象的done属性是一个布尔值,用来判断有没有读完;value属性是一个 arrayBuffer 数组,表示内容块的内容,
* 而value.length属性是当前块的大小。
*/
const {done, value} = await reader.read();
if (done) {
break;
}
console.log(`Received ${value.length} bytes`)
}
fetch 配置选项
const response = fetch(url, {
method: "GET",
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
});
- cache 处理缓存
- default:默认值,先在缓存里面寻找匹配的请求。
- no-store:直接请求远程服务器,并且不更新缓存。
- reload:直接请求远程服务器,并且更新缓存。
- no-cache:将服务器资源跟本地缓存进行比较,有新的版本才使用服务器资源,否则使用缓存。
- force-cache:缓存优先,只有不存在缓存的情况下,才请求远程服务器。
- only-if-cached:只检查缓存,如果缓存里面不存在,将返回504错误。
- mode 请求模式
- cors:默认值,允许跨域请求。
- same-origin:只允许同源请求。
- no-cors:请求方法只限于 GET、POST 和 HEAD,并且只能使用有限的几个简单标头,不能添加跨域的复杂标头,相当于提交表单所能发出的请求。
- credentials 是否发送cookie
- same-origin:默认值,同源请求时发送 Cookie,跨域请求时不发送。
- include:不管同源请求,还是跨域请求,一律发送 Cookie。
- omit:一律不发送。
-
keepalive 保持连接
keepalive属性用于页面卸载时,告诉浏览器在后台保持连接,继续发送数据。 -
redirect 跳转处理
- follow:默认值,fetch()跟随 HTTP 跳转。
- error:如果发生跳转,fetch()就报错。
- manual:fetch()不跟随 HTTP 跳转,但是response.url属性会指向新的 URL,response.redirected属性会变为true,由开发者自己决定后续如何处理跳转。
-
referrer
referrer属性用于设定fetch()请求的referer标头。 -
referrerPolicy
referrerPolicy属性用于设定Referer标头的规则。
- no-referrer-when-downgrade:默认值,总是发送Referer标头,除非从 HTTPS 页面请求 HTTP 资源时不发送。
- no-referrer:不发送Referer标头。
- origin:Referer标头只包含域名,不包含完整的路径。
- origin-when-cross-origin:同源请求Referer标头包含完整的路径,跨域请求只包含域名。
- same-origin:跨域请求不发送Referer,同源请求发送。
- strict-origin:Referer标头只包含域名,HTTPS 页面请求 HTTP 资源时不发送Referer标头。
- strict-origin-when-cross-origin:同源请求时Referer标头包含完整路径,跨域请求时只包含域名,HTTPS 页面请求 HTTP 资源时不发送该标头。
- unsafe-url:不管什么情况,总是发送Referer标头。
- signal 取消请求的实例
signal属性指定一个 AbortSignal 实例,用于取消fetch()请求
let controller = new AbortController();
setTimeout(() => controller.abort(), 1000);
try {
let response = await fetch('/long-operation', {
signal: controller.signal
});
} catch(err) {
if (err.name == 'AbortError') {
console.log('Aborted!');
} else {
throw err;
}
}
参考: https://www.ruanyifeng.com/blog/2020/12/fetch-tutorial.html