目录
1. Ajax请求服务介绍
- xhr: new XHLHttpRequest().open()/send()。偏向底层
- JQuery: 对xhr进行了封装。提供$get、$post等API。封装了太多DOM操作,不适合Vue
- axios: 基于promise的网络请求库,支持请求拦截器和响应拦截器,体积小,只有JQuery的1/4
- fetch:
Window.prototype
上直接有这个方法,也是基于promise的。但是会将返回的请求包两层promise,需要两次.then才能拿到请求,IE浏览器兼容性差
2. axios的安装
使用命令cnpm install axios
安装项目包
3. Vue跨域问题介绍和解决方案
- Vue使用Axios请求不同端口的服务,会出现类似下面的错误。即CORS跨域问题
Access to XMLHttpRequest at 'http://localhost:5000/students' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
- 只要【协议名】【IP】【端口】不同的服务请求就会出现跨域问题
- 出现跨域问题,服务器能接收到请求,浏览器也能接收到数据,但是浏览器发现存在跨域问题,就对数据进行拦截,Axios出现error报错
- 解决跨域问题的方法
- 服务器可以给Header中配置Access-Control-Allow-Origin,这样浏览器就不会进行数据的拦截,但是安全性不高
- jsonp解决跨域问题,借助script标签的src属性,在引入外部资源的时候,不受同源策略限制,需要前后端配置,而且只能解决get请求跨域问题,所以用的少
- 配置代理服务器。代理服务器和运行的Vue服务在同一台服务器,而且端口是一样的。虽然代理服务器和返回数据的服务器端口不一样,但是他们之间通信不用前端的Ajax,即不存在跨域问题。代理服务器种类
- Nginx
- vue-cli
4. 使用vue-cli配置开发环境代理服务
4.1 简单配置
在vue.config.js配置。这种方式只能配置一个接收请求的服务器
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
devServer: {
// 接收请求的服务器IP和端口
proxy: 'http://localhost:5000'
}
})
App.vue:Axios发送请求示例如下:
- axios发送的请求,是代理服务器的IP和端口
- 如果发送请求的资源在public目录下存在,如http://localhost:8080/favicon.ico,则不会向服务器发出请求
<template>
<div>
<button @click="getStudents">获取学生信息</button>
</div>
</template>
<script>
import axios from 'axios'
export default {
name:'App',
methods: {
getStudents(){
// 代理服务器的IP和端口
axios.get('http://localhost:8080/students').then(
response => {
console.log('请求成功了',response.data)
},
error => {
console.log('请求失败了',error.message)
}
)
}
}
}
</script>
4.2 复杂配置
- 可以配置多个接收请求的服务器。可以配置请求URL访问路径前缀
- 如果使用vite构建的项目,可以参考vite服务器选项server-proxy
在vue.config.js配置:axios请求的路径是http://localhost:8080/api1/students,最终代理服务器发送的请求url是http://localhost:5000/students
devServer: {
proxy: {
// 请求的URL符合前缀才走代理
'/api1': {
target: 'http://localhost:5000',
// 匹配以/api1开头的路径,然后将/api1替换成''
pathRewrite:{'^/api1':''},
ws: true, // 用于支持websocket
changeOrigin: true // 默认是true, 代理服务器告诉请求的服务器,我的端口和你一样是5000。如果是false,则告诉请求的服务器我是代理服务器,我的端口是8080
},
'/api2': {
target: 'http://localhost:5001',
pathRewrite:{'^/api2':''},
ws: true,
changeOrigin: true
}
}
}
App.vue
<template>
<div>
<button @click="getStudents">获取学生信息</button>
<button @click="getCars">获取汽车信息</button>
</div>
</template>
<script>
import axios from 'axios'
export default {
name:'App',
methods: {
getStudents(){
axios.get('http://localhost:8080/api1/students').then(
response => {
console.log('请求成功了',response.data)
},
error => {
console.log('请求失败了',error.message)
}
)
},
getCars(){
axios.get('http://localhost:8080/api2/cars').then(
response => {
console.log('请求成功了',response.data)
},
error => {
console.log('请求失败了',error.message)
}
)
}
}
}
</script>
4.3 二次封装
-
目的:
- 利用axios请求拦截器功能(一般可以在headers中携带公共的参数,如token)
- 利用axios响应拦截器功能(可以简化服务器返回的数据, 和处理http网络错误)
-
二次封装代码如下:
import axios from 'axios'
import {ElMessage} from 'element-plus'
// 创建一个axios实例, 可以设置基础路径、超时时间
const request = axios.create({
baseURL: '/api',
timeout: 5000
})
// 请求拦截器
request.interceptors.request.use((config) => {
config.headers.token = 123456
return config
})
// 响应拦截器
request.interceptors.response.use((response) => {
return response.data
}, (error) => {
// 处理http网络错误
let status = error.response.status
switch (status) {
case 400 | 404:
// 错误提示信息
ElMessage({
type: 'error',
message: error.response.message
})
break
default:
ElMessage({
type: 'error',
message: '请求出错了'
})
}
return Promise.reject(new Error(error.message))
})
export default request
二次封装的request的使用如下:
import request from "request"
request.get('/user').then(res => {
console.log(res)
})
5. 集成vue-resource发送Ajax请求
vue-resource也是基于promise的。使用命令cnpm install vue-resource
安装vue-resource的项目包
使用示例:
App.vue:直接调用VueComponent.$http发送请求
<template>
<div>
<button @click="getGithubUsers">获取Github的用户信息</button>
</div>
</template>
<script>
export default {
name:'App',
data() {
return {
uname:'test'
}
},
methods: {
getGithubUsers(){
// github服务器给我们解决了跨域问题
this.$http.get(`https://api.github.com/search/users?q=${this.uname}`).then(
response => {
console.log('请求成功了',response.data)
},
error => {
console.log('请求失败了',error.message)
}
)
}
}
}
</script>
main.js:使用vueResourceEsm插件
import Vue from 'vue'
import App from './App.vue'
import vueResourceEsm from "vue-resource";
Vue.config.productionTip = false
// 使用插件
Vue.use(vueResourceEsm)
new Vue({
el:'#app',
render: h => h(App)
})