异步(基于 Promise)、与 XMLHttpRequest 类似
全局的 fetch()
方法用于发起获取资源的请求。它返回一个 promise,这个 promise 会在请求响应后被 resolve,并传回 Response 对象。
语法:Promise<Response> fetch(input[, init]);
1.fetch 是一个用于发起 HTTP 请求的原生 JavaScript 函数。与 axios 类似,我们也可以对 fetch 进行封装,使得在项目中使用起来更加方便。
以下是一个简单的 fetch 封装示例:
const fetch = (url, options) => {
// 对 options 参数进行处理
options = Object.assign(
{
credentials: 'same-origin'
},
options
);
// 发起请求
return window.fetch(url, options).then(response => {
// 对响应数据进行处理
if (response.status >= 200 && response.status < 300) {
return response.json();
} else {
return Promise.reject(new Error(response.statusText));
}
});
};
export default fetch;
2.fetch 缺点
fetch 本身是一个很好的发起 HTTP 请求的工具,但是它有一些缺点:
- 不支持超时处理。如果请求超时,fetch 不会自动中断请求,而是会一直等待服务器响应。
- 不支持自动重试。如果请求失败,fetch 不会自动重新发起请求。
- 不支持拦截器。在发起请求和接收响应时,无法通过拦截器对请求和响应进行处理。
因此,在实际项目中,我们通常会选择使用 axios 或者其他类似的库来发起 HTTP 请求。
3.改进
- 使用超时库。例如,你可以使用 "fetch-timeout" 库来为 fetch 添加超时处理。
import fetchTimeout from 'fetch-timeout';
const fetch = (url, options, timeout = 5000) => {
return fetchTimeout(url, options, timeout).catch(error => {
if (error.name === 'FetchTimeoutError') {
// 处理超时错误
} else {
// 处理其他错误
}
});
};
- 使用重试库。例如,你可以使用 "fetch-retry" 库来为 fetch 添加重试功能。
import fetchRetry from 'fetch-retry';
const fetch = (url, options, retries = 3, retryDelay = 1000) => {
return fetchRetry(url, options, retries, retryDelay).catch(error => {
// 处理错误
});
};
- 使用拦截器库。例如,你可以使用 "fetch-intercept" 库来为 fetch 添加拦截器功能。
import fetchIntercept from 'fetch-intercept';
fetchIntercept.register({
request: function(url, config) {
// 在发起请求之前做一些处理
return [url, config];
},
requestError: function(error) {
// 对请求错误做些什么
return Promise.reject(error);
},
response: function(response) {
// 对响应数据做一些处理
return response;
},
responseError: function(error) {
// 对响应错误做些什么
return Promise.reject(error);
}
});
// 使用 fetch 函数发起请求
fetch('/users')
.then(res => {
console.log(res);
})
.catch(error => {
console.log(error);
});
4.将超时、重试、拦截器等功能组合在一起使用
import fetchTimeout from 'fetch-timeout';
import fetchRetry from 'fetch-retry';
import fetchIntercept from 'fetch-intercept';
const fetch = (url, options, timeout = 5000, retries = 3, retryDelay = 1000) => {
return fetchTimeout(url, options, timeout)
.then(response => {
if (response.status >= 200 && response.status < 300) {
return response.json();
} else {
return Promise.reject(new Error(response.statusText));
}
})
.catch(error => {
if (error.name === 'FetchTimeoutError') {
// 处理超时错误
} else {
return fetchRetry(url, options, retries, retryDelay).catch(error => {
// 处理其他错误
});
}
});
};
fetchIntercept.register({
request: function(url, config) {
// 在发起请求之前做一些处理
return [url, config];
},
requestError: function(error) {
// 对请求错误做些什么
return Promise.reject(error);
},
response: function(response) {
// 对响应数据做一些处理
return response;
},
responseError: function(error) {
// 对响应错误做些什么
return Promise.reject(error);
}
});
// 使用 fetch 函数发起请求
fetch('/users')
.then(res => {
console.log(res);
})
.catch(error => {
console.log(error);
});
5.使用示例
- 使用 fetch.get 发起 GET 请求:
fetch.get('/users').then(res => {
console.log(res);
});
- 使用 fetch.post 发起 POST 请求:
fetch.post('/users', {
body: JSON.stringify({
name: 'John',
age: 30
}),
headers: {
'Content-Type': 'application/json'
}
}).then(res => {
console.log(res);
});
- 使用 fetch.put 发起 PUT 请求:
fetch.put('/users/1', {
body: JSON.stringify({
name: 'John',
age: 30
}),
headers: {
'Content-Type': 'application/json'
}
}).then(res => {
console.log(res);
});
- 使用 fetch.delete 发起 DELETE 请求:
fetch.delete('/users/1').then(res => {
console.log(res);
});
6.总结
不管使用哪种库来发起 HTTP 请求,都要注意确保代码的可读性和可维护性。