consumed函数:
- function consumed(body) {
- if (body.bodyUsed) {
- return Promise.reject(new TypeError('Already read'))
- }
- body.bodyUsed = true
- }
每次调用text()、json()等函数后会将bodyUsed变量变为true,用来标识返回值已经读取过了,下一次再读取直接抛出TypeError('Already read')。这也遵循了原生fetch的原则:
因为Responses对象被设置为了 stream 的方式,所以它们只能被读取一次
十、fetch的坑点
VUE的文档中对fetch有下面的描述:
使用fetch还有很多别的注意事项,这也是为什么大家现阶段还是更喜欢 axios 多一些。当然这个事情在未来可能会发生改变。
由于fetch是一个非常底层的API,它并没有被进行很多封装,还有许多问题需要处理:
- 不能直接传递JavaScript对象作为参数
- 需要自己判断返回值类型,并执行响应获取返回值的方法
- 获取返回值方法只能调用一次,不能多次调用
- 无法正常的捕获异常
- 老版浏览器不会默认携带cookie
- 不支持jsonp
十一、对fetch的封装
请求参数处理
支持传入不同的参数类型:
- function stringify(url, data) {
- var dataString = url.indexOf('?') == -1 ? '?' : '&';
- for (var key in data) {
- dataString += key + '=' + data[key] + '&';
- };
- return dataString;
- }
- if (request.formData) {
- requestrequest.body = request.data;
- } else if (/^get$/i.test(request.method)) {
- request.url = `${request.url}${stringify(request.url, request.data)}`;
- } else if (request.form) {
- request.headers.set('Content-Type', 'application/x-www-form-urlencoded;charset=UTF-8');
- request.body = stringify(request.data);
- } else {
- request.headers.set('Content-Type', 'application/json;charset=UTF-8');
- request.body = JSON.stringify(request.data);
- }
cookie携带
fetch在新版浏览器已经开始默认携带同源cookie,但在老版浏览器中不会默认携带,我们需要对他进行统一设置:
- request.credentials = 'same-origin'; // 同源携带
- request.credentials = 'include'; // 可跨域携带
异常处理
当接收到一个代表错误的 HTTP 状态码时,从 fetch()返回的 Promise 不会被标记为 reject, 即使该 HTTP 响应的状态码是 404 或 500。相反,它会将 Promise 状态标记为 resolve (但是会将 resolve 的返回值的 ok 属性设置为 false ),仅当网络故障时或请求被阻止时,才会标记为 reject。
因此我们要对fetch的异常进行统一处理
- .then(response => {
- if (response.ok) {
- return Promise.resolve(response);
- }else{
- const error = new Error(`请求失败! 状态码: ${response.status}, 失败信息: ${response.statusText}`);
- error.response = response;
- return Promise.reject(error);
- }
- });
返回值处理
对不同的返回值类型调用不同的函数接收,这里必须提前判断好类型,不能多次调用获取返回值的方法:.
- then(response => {
- let contentType = response.headers.get('content-type');
- if (contentType.includes('application/json')) {
- return response.json();
- } else {
- return response.text();
- }
- });
jsonp
fetch本身没有提供对jsonp的支持,jsonp本身也不属于一种非常好的解决跨域的方式,推荐使用cors或者nginx解决跨域,具体请看下面的章节。
fetch封装好了,可以愉快的使用了。
嗯,axios真好用...
十二、跨域总结
谈到网络请求,就不得不提跨域。
浏览器的同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。通常不允许不同源间的读操作。
跨域条件:协议,域名,端口,有一个不同就算跨域。
下面是解决跨域的几种方式:
nginx
使用nginx反向代理实现跨域,参考我这篇文章:前端开发者必备的nginx知识
cors
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求。
(编辑:ASP站长网)
|