Fetch API提供了处理网络请求与响应的JavaScript接口。它提供了一个全局的fetch()
函数以轻松合理地异步获取网络资源。
fetch
请求的规则与jQuery.ajax()
有两点不同:
fetch
不会因为HTTP错误状态码而不返回Promise
,如状态码为404
/500
等。它会正常解析请求(将ok
状态置为否)。只有在网络错误或者某些因素阻止请求完成的情况下,fetch
才会不返回Promise
。fetch
默认情况下不会发送和接收任何服务器返回的cookie
,这会导致某些需要保持用户会话有效的站点产生未授权的请求错误。如需发送cookie
,需在请求的初始化选项中设置credentials
。
最简单的fetch
请求示例
// 发起网络请求
const response = await fetch('http://example.com/movie.json');
// 将响应对象解析为json
const myJson = await response.json();
// 将json对象转换为string并输出到控制台
console.log(JSON.stringify(myJson));
提供请求参数
fetch()
函数可以提供一个额外的init
对象参数来配置网络请求的相关信息。
见代码
try {
const data = await postData('http://example.com/answer', { 'answer': 42 });
console.log(JSON.stringify(data));
} catch (error) {
console.error(error);
}
async function postData(url = '', data = {}) {
// 默认的options会被标记为 *
const response = await fetch(url, {
method: 'POST', // 请求方法,GET/POST/PUT/DELETE等
mode: 'cors', // 跨域请求配置,no-cors/*cors/same-origin
cache: 'no-cache', // 缓存策略,*default/no-cache/reload/force-cache/only-if-cached
credentials: 'same-origin', // 是否发送cookie,*same-origin/include/omit
headers: {
'Content-Type': 'application/json', // body内容类型,'application/x-www-form-urlencoded'
}
redirect: 'follow', // 重定向,*follow/manual/error
referrer: 'no-referrer', // 请求来源,no-referrer, *client
body: JSON.stringify(data) // body数据类型必须与headers中的`Content-Type`一致
});
return await response.json();
}
发送包含认证信息的请求
如需发送带有认证信息的请求,可以在init
对象参数中添加credentials
字段。
credential
的三种取值:
include
:总是在请求中包含cookie
same-origin
:仅在请求同源地址时携带cookie
omit
:在请求中忽略cookie
上传JSON数据
try {
const response = await fetch(url, {
method: 'POST', // or 'PUT'
body: JSON.stringify(data), // data can be `string` or {object}!
headers: {
'Content-Type': 'application/json'
}
});
const json = await response.json();
console.log('Success:', JSON.stringify(json));
} catch (error) {
console.error('Error:', error);
}
上传文件
const formData = new FormData();
const fileField = document.querySelector('input[type="file"]');
formData.append('username', 'abc123');
formData.append('avatar', fileField.files[0]);
try {
const response = await fetch('https://example.com/profile/avatar', {
method: 'PUT',
body: formData,
});
const result = await response.json();
console.log('Success', JSON.stringify(result));
} catch (error) {
console.error(error);
}
上传多个文件
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', photos.files[i]);
}
try {
const response = await fetch('https://example.com/posts', {
method: 'POST',
body: formData
});
const result = await response.json();
console.log('Success:', JSON.stringify(result));
} catch (error) {
console.error('Error:', error);
}
逐行处理文本
略
检查请求是否成功
精确检查fetch()
请求是否成功,应先检查fetch()
是否返回了Promise
,再检查响应的状态码ok
是否正常。例如
try {
const response = await fetch('flowers.jpg');
if (!response.ok) {
throw new Error('Network response was not ok.');
}
const myBlob = await response.blob();
const URL = URL.createObjectURL(myBlob);
myImage.src = URL;
} catch (error) {
console.log('There has been a problem with your fetch operation: ', error.message);
}
自定义请求对象参数
可以使用Request()
构造器创建自定义的请求对象作为fetch()
的参数,而无需传入uri
路径。例如:
const myHeaders = new Headers();
const myInit = {
method: 'GET',
headers: myHeaders,
mode: 'cors',
cache: 'default'
};
const myRequest = new Request('flowers.jpg', myInit);
const response = await fetch(myRequest);
Request()
接收的参数和fetch()
完全一致,甚至可以传入一个已存在的request
对象来创建它的副本。例如:
const anotherRequest = new Request(myRequest, myInit);
通过创建副本以便于根据需要改变init
选项来重复利用request
/response
。拷贝必须在body
被使用前完成,而且即使读取了副本请求而使用了body
数据,也会使原请求中的body
数据被标记为已使用。
注:还有另外一个
clone()
方法也可以创建副本。当原请求的body
已使用时,两个方法都会失败。但是,读取副本请求不会使body
对象在原请求中被标记为已使用。(someRequest.clone()
)
Headers
Headers
接口允许通过Headers()
初始化器创建自定义的请求头对象。此对象实际就是一个简单的Map
。
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');
操作请求头
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')); // [ ]
headers
的一个经典使用场景,是检测Content-Type
是否正确。例如:
try {
const response = await fetch(myRequest);
const contentType = response.headers.get('content-type');
if (!contentType || !contentType.includes('application/json')) {
throw new TypeError("Oops, we haven't got JSON!");
}
const json = await response.json();
/* process your JSON further */
} catch (error) {
console.log(error);
}
Guard
可以设置headers
的guard
属性以限制修改其属性内容。guard
属性的取值类型有:
none
:默认request
:禁止修改从请求中获取的请求头对象request-no-cors
:禁止修改从请求中获取的Request.mode
为no-cors
的请求头response
:禁止修改从响应中获取的请求头immutable
:将请求头标记为只读
Response Object
最常用的响应属性:
Response.status
:响应状态码,如200
Response.statusText
:对应于HTTP状态码的状态文本。默认为ok
Response.ok
:响应状态的便捷判断,当HTTP状态码在200
~299
之间时为true
。
React Native中的Fetch
发起网络请求
最简单的请求方法,直接将URL作为参数传给fetch
调用即可。
fetch('https://mywebsite.com/mydata.json');
同理,可以传递init
对象提供额外的请求参数。例如:
fetch('https://mywebsite.com/endpoint/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
firstParam: 'yourValue',
secondParam: 'yourOtherValue',
})
})
处理服务器响应数据
fetch()
会返回一个Promise
对象`,因此可以简化异步代码编写风格。例如:
function getMoviesFromApiAsync() {
return fetch('https://facebook.github.io/react-native/movies.json', {
method: 'GET',
cache: 'no-cache'
})
.then((response) => response.json())
.then((responseJson) => {
return responseJson;
})
.catch((error) => {
console.error(error);
});
}
也可以使用ES2017的async
/await
语法这样写:
async function getMoviesFromApi() {
try {
let response = await fetch('https://facebook.github.io/react-native/movies.json');
let responseJson = await response.json();
return responseJson;
} catch (error) {
console.error(error);
}
}
注意必须在末尾处处理错误,否则程序可能会发生异常。
利用Promise
来封装网络请求组件
class NetworkUtils {
static get(url) {
return new Promise((resolve, reject) => {
fetch(url)
.then(response => response.json())
.then(result => resolve(result))
.catch(error => reject(error))
})
}
static post(url, params) {
return new Promise((resolve, reject) => {
fetch(url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
})
.then(response => response.json())
.then(result => resolve(result))
.catch(error => reject(error))
})
}
}