Fetch 与 Axios

原文: 使用Fetch 、 axios文档

什么是 fetch ? #

以前通过JS进行网络请求都是使用ajax也就是XMLHttpRequest实现的。如果用原生方式实现起来比较麻烦。

Fetch API是浏览器提供的一个代替XMLHttpRequest的新方法。

怎么使用 fetch ? #

最简单的形式:

1
2
3
4
5
6
7
8
fetch('http://example.com/movies.json')
.then(function(response) {
  // return response.text();
  return response.json();
})
.then(function(myJson) {
  console.log(myJson);
});

⚠️需要注意:

  1. fetch()方法返回的是promise
  2. Http状态码404或者500时也是resolve,但是会将resolve的返回值的ok属性设置为false
  3. 只有当网络故障或者请求被阻止时才会是reject
  4. resolve中进行response.json()才能拿到返回数据。
  5. response.json()会读取body,如果是json格式的,会将其转化。如果是不是json要用response.text()

怎么设置 method、header等参数呢? #

fetch() 方法接受第二个可选参数——一个对象——用来设置请求的参数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
fetch(url, {
  body: JSON.stringify(data), // must match 'Content-Type' header
  cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
  credentials: 'same-origin', // include, same-origin, *omit
  headers: {
    'user-agent': 'Mozilla/4.0 MDN Example',
    'content-type': 'application/json'
  },
  method: 'POST', // *GET, POST, PUT, DELETE, etc.
  mode: 'cors', // no-cors, cors, *same-origin
  redirect: 'follow', // manual, *follow, error
  referrer: 'no-referrer', // *client, no-referrer
})

⚠️credentials: 'include' 这个字段可以让请求带上 cookie 。

上传JSON数据 #

⚠️需要设置header'Content-Type': 'application/json'

1
2
3
4
5
6
7
fetch(url, {
  method: 'POST', // or 'PUT'
  body: JSON.stringify(data), // data can be `string` or {object}!
  headers: new Headers({
    'Content-Type': 'application/json'
  })
})

上传文件 #

⚠️需要使用FormData类作为requestbody

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
var formData = new FormData();
var fileField = document.querySelector("input[type='file']");

formData.append('username', 'abc123');
formData.append('avatar', fileField.files[0]);

fetch('https://example.com/profile/avatar', {
  method: 'PUT',
  body: formData
})

什么是 axios ? #

它是一个库,可以用Promise的方式进行网络请求。

怎么使用 axios ? #

最简单的几种方式 #

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// get请求1
axios.get('/user?ID=12345').then();
// get请求2
axios.get('/user',{
  params:{id:12345}
}).then();
// post请求
axios.post('/user', {
    firstName: 'Fred',
    lastName: 'Flintstone'
})

同时进行多个请求 #

几个请求都成功后,进行后续操作

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
function getUserAccount() {
  return axios.get('/user/12345');
}

function getUserPermissions() {
  return axios.get('/user/12345/permissions');
}

axios.all([getUserAccount(), getUserPermissions()])
  .then(axios.spread(function (acct, perms) {
    // Both requests are now complete
  }));

使用async/await #

1
2
3
4
5
6
7
8
async function getUser() {
  try {
    const response = await axios.get('/user?ID=12345');
    console.log(response);
  } catch (error) {
    console.error(error);
  }
}

创建实例——统一配置、设置,统一处理请求、响应 #

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
const instance = axios.create({
  baseURL: 'https://some-domain.com/api/',
  timeout: 1000,
  headers: {'Authorization': 'foobar'},
  transformRequest: [function (data, headers) {
    // Do whatever you want to transform the data
    return data;
  }],
  transformResponse: [function (data) {
    // Do whatever you want to transform the data
    return data;
  }],
});

注意⚠️

  1. 没有transformResponse属性时,resopnse中的data是一个对象。
  2. 加了transformResponse属性后(即便它是空的方法),resopnse的data会变成字符串。
  3. 如果想对response做统一处理,可以在拦截中做。

拦截响应或请求 #

这里的data会受到上面的transformResponse影响,不加的时候就是对象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// 响应拦截器
instance.interceptors.response.use(function (response) {
    // 对响应数据做点什么
    if (response.data.error === 1500) {
        console.warn('ed_token失效,error code:1500');
        window.localStorage.removeItem('ed_token')
        window.localStorage.removeItem('ed_user_info')
        document.dispatchEvent(new Event('authErrorAngToLogin'))
        // return Promise.reject(response.data);
    } else {
        response.data = response.data.data
    }

    return response;
}, function (error) {
    // 对响应错误做点什么
    return Promise.reject(error);
});

初始的header的Authorization可能是无效的,需要在登录后更新

1
my_axios.defaults.headers['Authorization'] = result.token;

上传文件 #

两点需要注意:

  1. file文件对象使用Form类存放
  2. content-typemultipart/form-data
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
var formData = new FormData();
formData.set('file', file)
axios.post(
  'https://develop.com/upload',
  formData,
  {
    headers: {
      'Authorization': 'token',
      'Content-Type': 'multipart/form-data'
    }
  }
).then(res =>
    console.log(res.data)
)

取消请求 #

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
const login = async (params, cancelToken) => {
  try {
    const response = await axios.post(`/user`, params, cancelToken);
    return response;
  } catch (error) {
    if (axios.isCancel(error)) {
      console.log('Request canceled', error.message);
    } else {
      message.error(error.message);
    }
  }
},

其中cancelToken每次调用login时需要重新生成:

1
2
const CancelToken = axios.CancelToken;// 可以全局一个
const source = CancelToken.source();// 每次请求都要时调用生成cancelToken