入门 - Vue中使用axios原理分析及解决前端跨域问题
1. 什么是Axios?
Axios(ajax i/o system)
,是Vue创建者主推的请求发送方式,因其简单的配置与良好的性能被前端爱好者所喜爱。众所周知,在进行网页设计时经常需要从后端拿数据,在Web应用初期会将整个页面或者文档直接拿过来,随着Web应用的发展,人们对性能的不断提升,逐渐向无页面刷新从后端获取数据,而axios就是其中一种新兴、火热的方式。在学习Vue中使用axios时,不需要太过于了解请求的发送过程,但需要对各种请求方式有一个大致的认识。本文将会从0到1的介绍vue中如何使用axios,并结合项目实例加深大家印象。
注意:第一部分只是带大家了解一下axios是什么以及其如何使用,具体项目中的应用还要看第二三部分。
1.1. axios概念
axios
是一个基于promise 的 HTTP 库,可以用在浏览器和node.js
中。
axios
本质上也是对原生XHR(XMLHttpRequest
)的封装,只不过它是Promise的实现版本,符合最新的ES规范。
新手可能容易弄混ajax与axios两个概念:
Ajax(Asynchronous Javascript And XML)
不是一种编程语言,而是一种用于创建更好更快以及交互性更强的Web应用程序的技术。这种技术可以用到各种各样的库上。Axios(ajax i/o system)
是基于Ajax技术实现的一种库,市面上还有许多这样的库例如JQuery。
Axios
通常具有以下特点:
- 从浏览器创建 XMLHttpRequests
- 从 node.js 创建 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求和响应数据
- 取消请求
- 自动转换JSON数据
- 客户端支持防御XSRF
- 主流及大众浏览器宽泛的支持
- 配置简单、安装简便
1.2. vue中使用axios
第一步:安装(安装起来灰常简单按照步骤执行即可)
- 首先进入你的项目中src所在的目录
- 然后进入cmd命令行
- 执行npm install axios
- 即可
第二步:引入项目
import axios from "axios"
第三步:发送请求并获取响应
这里仅仅是发送请求的其中一种方式(调用api),发送请求方式有两种:
- 传入对象发送;
- 调用api发送。
//请求github接口,根据用户名获取用户头像
axios.get(`https://api.github.com/search/users?q=${this.tempstr}`).then(
// 响应成功(response存放了所有的响应信息)
response=>{
this.$bus.$emit("getDatas",{"objData":response.data.items,"isLoding":false,"error":""})
},
//出错
error=>{
console.log(error.message)
this.$bus.$emit("getDatas",{"objData":[],"isLoding":false,"error":error.message})
}
)
1.3. Axios两种请求方式
本质都是发送了一个get请求,一种是调用接口,一种是传入对象。在项目中使用时一般先创建一个axios对象对其进行二次封装,并添加请求、响应拦截器。这里只作为了解。
①.调用接口
this.$axios.get('后端url',{
params: {
id:1
}
}).then(res=>{
console.log(res.data);
},err=>{
console.log(err);
})
②.传入对象
传入对象常用配置:
参数名 | 作用 |
---|---|
baseURL | 请求的域名,基本地址,类型:String |
timeout | 请求超时时长,单位ms,类型:Number |
url | 请求路径,类型:String |
method | 请求方法,类型:String |
headers | 设置请求头,类型:Object |
params | 请求参数,将参数拼接在URL上,类型:Object |
data | 请求参数,将参数放到请求体中,类型:Object |
this.$axios({
method: 'get',
url: '后端url',
params: {
id:1
}
}).then(res=>{
console.log(res.data);
},err=>{
console.log(err);
})
接下来将会对请求类型进行细化,介绍axios支持的请求类型。
1.4.Axios支持的请求类型
①.get请求
不带请求参数:
方式一: axios({ methods: 'get', url: '/ulr' })
方式二: axios.get('/url')
带请求参数:
方式一: axios.get('/url', {params: {id: 12}}) //请求的地址实际为 localhost:8080/url?id=12
方式二: axios({
methods: 'get',
url: 'url',
params: {
id:12
}
})
②.post请求
let data = {}
let config = {}
方式一: axios.post('/url',data,config)
方式二: axios({
methods: 'post',
url: '/url',
data: data,
config: config
})
③.put请求
该请求和post类似,只是请求方法接口不同,传入对象的methods不同
④.patch请求
该请求和post类似,只是请求方法接口不同,传入对象的methods不同
⑤.delete请求
axios.delete('/url', {params: {id: 12}}) #参数在url params很重要
axios.delete('/url', {data: {id: 12}}) #参数在请求体中 将params改为 data就行
2. 跨域问题解决方案
2.1. 什么是跨域问题?
由于浏览器的同源策略限制,进而产生跨域拦截问题。同源策略是浏览器最核心也最基本的安全功能;所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)。这里要着重强调的是跨域问题是因为浏览器的原因,请求响应都是正常的,响应结果也交给了浏览器,只是因为没有进行相应的配置浏览器不将数据拿给用户。
同源策略(Same origin policy
)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略在解决浏览器访问安全的同时,也带来了跨域问题,当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域。
跨域问题通常会抛出类似于下面的错误:
Access to XMLHttpRequest at 'http://43.143.232.114:8080/login' from origin 'http://localhost:8081' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
当然这种问题并不是没有解决方案的常见的方法有三种:前端对脚手架文件进行配置、nginx进行转发、后端写相应的字段配合。彻底解决跨域请求还需要了解一下简单请求与复杂请求的概念,这里主要是教大家在vue中使用axios,就不进行过多的赘述了,后面会专门出一篇文章教大家彻底理解并解决跨域问题。
2.2. 方案一:在Vue中进行配置
在前面介绍创建vue项目时曾提到过vue.config.js配置文件,这个配置文件可以对我们的项目做一些个性化定制,也是我们解决跨域问题的重要途径之一。vue快速搭建一个项目在上面文章中有对Vue基础配置进行介绍。
配置文件内容如下:
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
lintOnSave:false, /*关闭语法检查*/
//开启代理服务器(方式一)两个留一个即可
devServer: {
proxy: 'http://localhost:5000'
},
//开启代理服务器(方式二)
devServer: {
proxy: {
//第一个跨域代理
'/server1': {
target: 'http://localhost:5000',
// 这样的写法是一种简写,会将原始路由中的/server1使用空格替换掉
pathRewrite:{'^/server1':''},
ws: true, //用于支持websocket
//用于控制请求头中的host值,这个为true,会将请求头中的host字段变为target设置的值
changeOrigin: true
},
//第二个跨域代理
'/server2': {
target: 'http://localhost:5001',
pathRewrite:{'^/server2':''},
ws: true, //用于支持websocket
changeOrigin: true //用于控制请求头中的host值
}
}
}
})
2.3. 方案二:使用Nginx转发
使用这种方法需要有Nginx的基础知识,由于篇幅有限这里只提供思路,不进行细致的介绍了:
- 在前端主机安装Nginx
- 配置Nginx主配置文件进行路由转发
- 启动Nginx服务器
2.4. 方案三:后端配合
这里做的工作就是将响应头字段中的指定字段添加上即可,这里给出Golang的跨域请求设置
//resp是响应对象
resp.Header().Set("Access-Control-Allow-Origin", "*") //允许访问所有域
3. 封装Axios对象
项目中使用axios时,并不是直接使用其接口,通常会将其进行封装,对其功能进行定制。
以下实例就是对axios原有对象进行定制封装,然后实现自己的接口并调用
3.1. 创建axios实例
/**
* 封装的axios
*/
import axios from 'axios'
import qs from 'querystring'
/**
* 错误函数 解析常用的http状态码
* 2xx:成功
* 3xx: 重定向
* 4xx: 资源不存在
* 5xx:服务器错误
*
*/
const ErrorHandle=(status, info) => {
switch (status) {
case 400:
console.log('400-表示请求报文中存在语法错');
break;
case 401:
console.log('401-未经许可,需要通过HTTP认证');
break;
case 403:
console.log('403-服务器拒绝该次访问(访问权限出现问题)');
break;
case 404:
console.log('404-表示服务器上无法找到请求的资源');
break;
case 500:
console.log('500-表示服务器在执行请求时发生了错误,\
也有可能是web应用存在的bug或某些临时的错误时;');
break;
case 503:
console.log('503-表示服务器暂时处于超负载或正在进行停机维护,无法处理请求');
break;
default:
console.log(info);
break;
}
}
//自定义新建一个 axios 实例
const install = axios.create({
baseURL:process.env.VUE_APP_BASE_URL,//网络请求的基础路径,这里是vue脚手架运行时开启的端口
timeout: 5000,//请求等待时间 时间到了后台没有返回数据 请求中段
})
3.2. 请求拦截器
以下代码将在请求发送出去之前执行,通常用于对请求中的数据进行指定格式化的转换
//拦截器
// 添加请求拦截器
install.interceptors.request.use(function (config) {
console.log('添加请求拦截器',config);
//处理post请求发送的参数格式
if(config.method==='post'){
config.data = qs.stringify(config.data)//{} 转 xx=xx&xx=xx
}
//配置请求token
let token= localStorage.getItem('token')
if(token){
config.headers.Authorization=token;
}else{
return config;
}
// console.log('添加请求拦截器--config',config);
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
3.3. 响应拦截器
以下代码用于响应来到前执行,通常用于检验响应有没有出错
// 添加响应拦截器
install.interceptors.response.use(
response=>response,
error=>{
console.log('响应拦截器错误',error);
let { response } = error;
// 对响应错误做点什么
ErrorHandle(response.status,response.info)
});
最终将axios暴露出去
export default install;
3.4. 导入定制的axios并使用
以下两个文件可以装进一个api文件夹下,专门负责网络请求
base.js
const base ={
host:'http://localhost:8989',//基础域名
/*
...
指定接口对应的路由
*/
}
export default base;
index.js
/**
* 请求的方法
*/
import base from './base'
//导入二次封装的axios文件
import axios from '../utils/request'
//axios接口配置基础地址
// axios.defaults.baseURL = process.env.VUE_APP_BASE_URL;
const api = {
//自己指定接口,例如下面制定的一个接口
/**
* 登录接口
*/
getLogin(params) {//params={username:'',password:''}
return axios.post(base.login, params)
},
}
export default api
做完上述工作,就可以直接在我们的项目中引入并使用,想用什么功能的接口自己封装即可(不亦乐乎)。
main.js
import api from './api/index'
Vue.prototype.$api = api;