1.选择什么网络模块?
选择一: 传统的Ajax是基于XMLHttpRequest(XHR)
为什么不用它呢?
- 非常好解释, 配置和调用方式等非常混乱.
- 编码起来看起来就非常繁琐.
- 所以真实开发中很少直接使用, 而是使用jQuery-Ajax
选择二: 在前面的学习中, 我们经常会使用jQuery-Ajax
相对于传统的Ajax非常好用.
为什么不选择它呢?
- 首先, 我们先明确一点: 在Vue的整个开发中都是不需要使用jQuery了.
- 那么, 就意味着为了方便我们进行一个网络请求, 特意引用一个jQuery, 不合理
选择三:axios
其实官方在Vue1.x的时候, 推出了Vue-resource.但是后来作者在说明不再继续更新和维护vue-resource了,所以现在推荐axios
axios有非常多的优点, 并且用起来也非常方便.
2.JSONP
在前端开发中, 我们一种常见的网络请求方式就是JSONP
- 使用JSONP最主要的原因往往是为了解决跨域访问的问题.
JSONP的原理是什么呢?
- JSONP的核心在于通过
<script>
标签的src来帮助我们请求数据. - 原因是我们的项目部署在domain1.com服务器上时, 是不能直接访问domain2.com服务器上的资料的.
- 这个时候, 我们利用
<script>
标签的src帮助我们去服务器请求到数据, 将数据当做一个javascript的函数来执行,
并且执行的过程中传入我们需要的json. - 所以, 封装jsonp的核心就在于我们监听window上的jsonp进行回调时的名称.
3.axios
功能特点:
- 在浏览器中发送 XMLHttpRequests 请求
- 在 node.js 中发送 http请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求和响应数据
支持多种请求方式:
- axios(config)
- axios.request(config)
- axios.get(url[, config])
- axios.delete(url[, config])
- axios.head(url[, config])
- axios.post(url[, data[, config]])
- axios.put(url[, data[, config]])
- axios.patch(url[, data[, config]])
axios的使用
npm install axios --save
(1)最基本使用
import axios from 'axios'
//axios本身可以返回一个promise,调用内部resolve
axios({
// url:'httpbin.org/'
url:'http://123.207.32.32:8000/home/multidata',
method:'get'//默认情况下get请求
}).then(res => {
console.log(res)
})
(2)专门针对get请求的参数拼接
axios({
url:'http://123.207.32.32:8000/home/data',
params:{
type:'pop',
page:1
},
method:'get'
}).then(res => {
console.log(res)
})
(3)axios.get()
// 为给定 page 的 data 创建请求
axios.get('http://123.207.32.32:8000/home/data?type=sell&page=3')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
// 可选地,上面的请求可以这样做
axios.get('http://123.207.32.32:8000/home/data', {
params: {
type:'pop',
page:1
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
执行 POST 请求
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
(4)axios.all执行多个并发请求
axios.all([axios({}),axios({})]).then(=>res{})
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) {
// 两个请求现在都执行完成
}));
axios.all([]) 返回的结果是一个数组res[0]、res[1],使用 axios.spread 可将数组 [res1,res2] 展开为 res1, res2
axios.all([axios.get('http://123.207.32.32:8000/home/multidata'),
axios.get('http://123.207.32.32:8000/home/data',{params:{type:'pop',page:1}})
])
.then(axios.spread((res1,res2) => {
console.log(res1);
console.log(res2);
}))
补充一个小小的知识点
数组的解构
const names = ['11','22','33']
//const name1 = names[0]
//const name2 = names[1]
//const name3 = names[2]
const [name1,name2,name3] = names
(5)全局配置defaults
axios.defaults.baseURL='http://123.207.32.32:8000'
axios.defaults.timeout=5000
axios.all([axios.get('/home/multidata'),
axios.get('/home/data',{params:{type:'pop',page:1}})
])
.then(axios.spread((res1,res2) => {
console.log(res1);
console.log(res2);
}))
(6)常见的配置选项
请求地址
- url: ‘/user’,
请求类型
- method: ‘get’,
请根路径
- baseURL: ‘http://www.mt.com/api’,
请求前的数据处理
- transformRequest:[function(data){}],
请求后的数据处理
- transformResponse: [function(data){}],
自定义的请求头
- headers:{‘x-Requested-With’:‘XMLHttpRequest’},
URL查询对象
(method: ‘get’,)
- params:{ id: 12 },
查询对象序列化函数
- paramsSerializer: function(params){ }
request body
(methos:‘post’)
- data: { key: ‘aa’},
超时设置s
- timeout: 1000,
跨域是否带Token
- withCredentials: false,
自定义请求处理
- adapter: function(resolve, reject, config){},
身份验证信息
- auth: { uname: ‘’, pwd: ‘12’},
响应的数据格式 json / blob /document /arraybuffer / text / stream
- responseType: ‘json’,
axios创建实例
为什么要创建axios的实例呢?
- 当我们从axios模块中导入对象时, 使用的实例是默认的实例.
- 当给该实例设置一些默认配置时, 这些配置就被固定下来了.
- 但是后续开发中, 某些配置可能会不太一样.
- 比如某些请求需要使用特定的baseURL或者timeout或者content-Type等.
- 这个时候, 我们就可以创建新的实例, 并且传入属于该实例的配置信息.
服务器以后不在同一个ip地址里,就不方便使用全局配置,我们要创建对应的axios实例
const instancel = axios.create({
baseURL:'http://123.207.32.32:8000',
timeout:5000
})
instancel({
url:'/home/multidata'
}).then(res => {
console.log(res);
})
instancel({
url:'/home/data',
params:{type:'pop',page:1}
}).then(res => {
console.log(res);
})
如果遇到不同的ip地址,再定义一个const instancel2 写上对应ip地址就好了
在每一个vue文件使用时在单独引入
HelloWorld.vue(这算一个子组件,注意要在父组件中引入)
<template>
<h2>{{categories}}</h2>
</template>
<script>
import axios from 'axios'
export default {
name: "HelloWorld",
data() {
return {
categories: ''
}
},
created() {//实例创建完成生命周期
axios({
url: 'http://123.207.32.32:8000/category'
}).then(res => {
this.categories = res;
})
}
}
</script>
父组件中
<template>
<div id="app">
<div>{{result}}</div>
<hello-world/>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld'
import axios from 'axios'
export default {
name: 'App',
components: {
HelloWorld
},
data() {
return {
result: ''
}
},
created() {
axios({
url: 'http://123.207.32.32:8000/home/multidata'
}).then(res => {
this.result = res;
})
}
}
</script>
但是如果不封装一个实例,每次我们用到axios都要单独引用一下,很麻烦,下面我们进行封装
import axios from 'axios'
//考虑到扩展就不用defaule了
export function request(config) {
//1.创建axios的实例
const instance = axios.create({
baseURL:'http://123.207.32.32:8000',
timeout:5000
})
//发送真正的网络请求
instance(config).then(res =>{
console.log(res);
}).catch(err => {
console.log(err);
})
}
console.log()但是我们不能在这个文件里进行传值呀,怎么传出去呢?
给request多添加两个参数 success, failure
方法一:
import axios from 'axios'
export function request(config, success, failure) {
//1.创建axios的实例
const instance = axios.create({
baseURL:'http://123.207.32.32:8000',
timeout:5000
})
//发送真正的网络请求
instance(config).then(res =>{
// console.log(res);
success(res)//回调数据
}).catch(err => {
// console.log(err);
failure(err)
})
}
再在main.js中封装一个request模块
import {request} from "./network/request";
request({
url:'/home/multidata'
},res =>{
console.log(res);
},err => {
console.log(err);
})
方法二
import axios from 'axios'
export function request(config) {
//1.创建axios的实例
const instance = axios.create({
baseURL:'http://123.207.32.32:8000',
timeout:5000
})
//发送真正的网络请求
instance(config.baseConfig).then(res =>{//config中取出baseConfig
config.success(res)//config中取出success,在这里进行回调1
}).catch(err => {
config.failure(err)//config中取出failure
})
}
main.js中
import {request} from "./network/request";
request({
baseConfig:{
},
success: function (res) {
},
failure: function (err) {
}
})
除了以上两种回调函数方式,我们一般在项目中用第三种方法,promise方式
方法三
request.js
import axios from 'axios'
export function request(config) {
return new Promise(((resolve, reject) => {
const instance = axios.create({
baseURL:'http://123.207.32.32:8000',
timeout:5000
})
//发送真正的网络请求
instance(config)
.then(res =>{
resolve(res)
})
.catch(err => {
reject(err)
})
}
))
}
main.js封装一个request模块
import {request} from "./network/request";
request({
url:'/home/multidata'
}).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
再或者request.js直接写成
面向request发送请求
export function request(config) {
const instance = axios.create({
baseURL:'http://123.207.32.32:8000',
timeout:5000
})
//发送真正的网络请求
return instance(config)
}
进入后再长按Ctrl进入AxiosInstance
也就是说我们定义的这个instance本身的返回值就是Promise
所以我们直接return instance,就可以了
封装好之后如果有一天axios不可用了,我们直接修改request.js中的引入,再修改export function request(config) {}
中的内容就可以了
axios拦截器的使用
axios提供了拦截器,用于我们在发送每次请求或者得到相应后,进行对应的处理。
import axios from 'axios'
export function request(config) {
//1.创建axios的实例
const instance = axios.create({
baseURL:'http://123.207.32.32:8000',
})
//2.axios拦截器
instance.interceptors.request.use(config =>{
console.log(config);
//请求拦截
return config//拦截掉之后还要原封不动的返回出去
},err =>{} );
instance.interceptors.response.use(res => {
//响应拦截
// console.log(res);
return res.data
},err =>{
console.log(err);
});
//3.发送真正的网络请求
return instance(config)
}
//封装一个request模块
import {request} from "./network/request";
request({
url:'/home/multidata'
}).then(res => {
console.log(res)
}).catch(err => {
// console.log(err)
})
拦截器中都做什么呢?
请求拦截
- 1.比如config中的一些信息不符合服务器的要求
- 2.比如每次发送网络请求时,都希望在界面中显示一个请求的图标(比如一个加载的图片)
- 3.某些网络请求(比如说登录),必须携带一些特殊的信息
- 请求拦截中错误拦截较少,通常都是配置相关的拦截
- 可能的错误比如请求超时,可以将页面跳转到一个错误页面中。
响应拦截:
- 响应的成功拦截中,主要是对数据进行过滤。上面代码中就对data进行了过滤
return res.data
- 响应的失败拦截中,可以根据status判断报错的错误码,跳转到不同的错误提示页面。
instance.interceptors.response.use(res => {
return res.data
},err =>{
console.log(err);
if (err && err.response) {
switch (err.response.status) {
case 400:
err.message = '请求错误'
break
case 401:
err.message = '未授权的防问'
break
}
}
return err
});
(以上内容根据微博“coderwhy”的vue视频课程整理,感谢王红元老师ღ( ´・ᴗ・` )比心)