基本操作
一个基本的fetch操作很简单。就是通过fetch请求,返回一个promise对象,然后在promise对象的then方法里面用fetch的response.json()等方法进行解析数据,由于这个解析返回的也是一个promise对象,所以需要两个then才能得到我们需要的json数据。
fetch('http://example.com/movies.json')
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(myJson);
});
为何不能直接使用基本操作
fetch规范与jQuery.ajax()主要有两种方式的不同:
1、当接收到一个代表错误的 HTTP 状态码时,比如400, 500,fetch不会把promise标记为reject, 而是标记为resolve,仅当网络故障时或请求被阻止时,才会标记为 reject。
2、默认情况下,fetch 不会从服务端发送或接收任何 cookies, 如果站点依赖于用户 session,则会导致未经认证的请求(要发送 cookies,必须设置 credentials 选项)。
从这里可以看出来,如果我们要在fetch请求出错的时候及时地捕获错误,是需要对response的状态码进行解析的。又由于fetch返回的数据不一定是json格式,我们可以从header里面Content-Type获取返回的数据类型,进而使用正确的解析方法。
使用async/awiait的原因
Promise 将异步操作规范化.使用then连接, 使用catch捕获错误, 堪称完美, 美中不足的是, then和catch中传递的依然是回调函数, 与心目中的同步代码不是一个套路.
为此, ES7 提供了更标准的解决方案 — async/await. async/await 几乎没有引入新的语法, 表面上看起来, 它就和alert一样易用。
var word = '123',
url = 'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd='+word+'&json=1&p=3';
(async ()=>{
try {
let res = await fetch(url, {mode: 'no-cors'});//等待fetch被resolve()后才能继续执行
console.log(res);//fetch正常返回后才执行
return res;//这样就能返回res不用担心异步的问题啦啦啦
} catch(e) {
console.log(e);
}
})();
代码
解析结果值
检查返回值的状态: 上面提到了,因为fetch不会自己reject,所以我们只能够通过抛出错误帮一下它啦。301和302是重定向的状态码,这个时候页面需要跳转一下,通过window.location实现是不是很perfer呢。
checkStatus(response) {//检查响应状态
if(response.status >= 200 && response.status < 300) {//响应成功
return response;
}
if(response.status === 301 || response.status === 302) {//重定向
window.location = response.headers.get('Location');
}
const error = new Error(response.statusText);
error.data = response;
throw error;
}
判断用哪个fetch的解析函数:这里通过headers的Content-Type判断使用哪个解析方法,因为解析也是异步的,所以还是用async/await让程序停在那里慢慢解析。
async parseResult(response) {//解析返回的结果
const contentType = response.headers.get('Content-Type');
if(contentType != null) {
if(contentType.indexOf('text') > -1) {
return await response.text()
}
if(contentType.indexOf('form') > -1) {
return await response.formData();
}
if(contentType.indexOf('video') > -1) {
return await response.blob();
}
if(contentType.indexOf('json') > -1) {
return await response.json();
}
}
return await response.text();
}
为了调用比较好看吧,写多一个processResult去调用者两个方法,然后在fetch的then里面就只需要用这个去得到结果啦。
async processResult(response) {
let _response = this.checkStatus(response)
_response = await this.parseResult(_response);
return _response;
}
fetch请求后台代码
把请求后台的代码都写在_request里面,然后get和post里面就封装一下参数。
async _request(url, init, headers = {}) {
try {
let options = _.assign(
{
credentials: 'include',//允许跨域
},
init
);
options.headers = Object.assign({}, options.headers || {}, headers || {});
let response = await fetch(url, options);
response = await this.processResult(response);//这里是对结果进行处理。包括判断响应状态和根据response的类型解析结果
return response;
} catch(error) {
throw error;
return null;
}
}
async get(api, data = {}, headers = {}, config = {}) {
const query = _.isEmpty(data) ? '' : `json=${encodeURIComponent(JSON.stringify(data))}`;
return await this._request(`${api}?${query}`, headers, {}, config);
}
async post(api, data = {}, headers = {}, config = {}) {//通过headers决定要解析的类型
const _headers = {
'Content-Type': 'application/x-www-form-urlencoded',
...headers,
};
let formBody = null;
if(_headers['Content-Type'] && _headers['Content-Type'].indexOf('application/x-www-form-urlencoded')>-1) {
formBody = new URLSearchParams();
for(let k in data) {//遍历一个对象
if(typeof(data[k]) === 'object') {
formBody.append(k, JSON.stringify(data[k]));
} else {
formBody.append(k, data[k]);
}
}
}
return await this._request(
api,
{
method: 'POST',
headers: _headers,
body: formBody,
},
{},
config,
)
}
how to use
把上面这些代码到写在一个http类里面
import 'isomorphic-fetch'
import 'es6-promise'
import _ from 'lodash';
class http {
checkStatus(response) {}
async parseResult(response) {}
async processResult(response) {}
async _request(url, init, headers = {}) {}
async get(api, data = {}, headers = {}, config = {}) {}
async post(api, data = {}, headers = {}, config = {}) {}
}
let http = new Http();
export default http;
然后调用的时候
import http from '../../common/http'
getData() {
//form类型
http.post('/api/submitComment', {a: 'hhhh'}).then((data) => {
console.log(data);//输出返回的数据
})
//json类型
http.post('/api/submitComment', {a: 'hhhh'}, {'content-type': 'application/json'
}).then((data) => {
console.log(data);//输出返回的数据
})
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。