Vue2.x笔记:请求后端接口
1. 在组件中请求后端接口
这里我首先使用easy-mock模拟了一个后端接口: https://192.168.5.98/mock/example
该接口接收get请求,返回体如下:
{
"status": "ok",
"code": "1",
"data": {
"message": "Hello world"
}
}
接下来尝试在vue组件中调用这个接口
第一步:安装axios
npm install axios --save
第二步:在组件中调用axios.get()方法请求后端接口
<template>
<div>
<div id="app">
<button @click="getMsg">获取数据</button>
<p v-if="message">{{message}}</p>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'App',
data() {
return {
message: ''
}
},
methods: {
getMsg() {
axios.get('https://192.168.5.98/mock/example').then(
response => {
console.log('请求成功', response.data);
this.message = response.data.data.message;
},
error => {
console.log('请求失败', error.message);
}
)
}
}
}
</script>
<style>
</style>
2. 配置代理解决跨域问题
如果请求失败,且浏览器Console显示Access to XMLHttpRequest at ... has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
这样的错误。
错误的原因是存在跨域问题。
跨域(Cross-Origin)是指浏览器的一种安全策略限制,即同源策略(Same-Origin Policy),它用于阻止一个域上的文档或脚本与另一个域上的资源进行交互,这里的“域”通常指的是协议、域名和端口号。也就是说,如果两个网页的协议、主机名或者端口号有任何一个不同,就被当作是不同的域,此时浏览器会实施同源策略,限制不同源之间的相互访问。
在vue-cli项目中,可以通过配置代理来解决跨域问题。
在vue.config.js文件中配置代理:
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
// 配置代理
devServer: {
proxy: 'http://后端IP:后端端口'
}
})
另一种配置方式:
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
// 配置代理
devServer: {
port: 8080, // 可选,设置开发服务器端口号,默认为8080
proxy: {
'/api': { // 匹配所有以 '/api' 开始的请求路径
target: 'http://192.168.5.98/mock', // 设置目标服务器的基础URL
changeOrigin: true, // 是否需要改变原始请求头部的host信息,如果是跨域请求则应设为true
pathRewrite: {
'^/api': '' // 将请求路径中'/api'这一段重写为空,目的是让请求能够匹配到目标服务器的实际路径,比如'/example'
},
secure: false, // 如果目标服务器使用HTTPS,但证书不可信,可以设为false绕过SSL验证
}
}
}
})
这样配置后,当在Vue应用中发起如 axios.get('/api/example')
的请求时,实际上会被代理到 http://192.168.5.98/mock/example
,从而规避了浏览器的同源策略限制。
3. axios二次封装与请求/响应拦截器
通过二次封装axios,可以配置自己的请求拦截器和响应拦截器。
请求拦截器:请求拦截器在实际发起HTTP请求之前执行。其主要作用包括但不限于:
- 统一添加请求头:如为所有请求自动添加认证Token、API版本号、用户标识等公共信息。
- 格式化请求数据:在发送请求前对请求体进行预处理或转换。
- 请求异常处理:在请求发送前进行条件检查,如若不符合条件则阻止请求发出。
- 请求缓存控制:根据特定条件决定是否从缓存中获取数据而非向服务器发送请求。
响应拦截器:响应拦截器在收到HTTP响应后、响应数据传递给请求回调之前执行。它的用途主要包括:
- 统一错误处理:对HTTP状态码进行判断,针对不同响应码执行相应的逻辑,如处理API错误码,统一弹框提示等。
- 数据格式化:对接收到的数据进行预处理或转换,如对JSON数据进行解析或进一步加工。
- 身份验证失败处理:如检测到401 Unauthorized状态码,自动跳转至登录页面或清除用户的授权信息。
- 响应缓存控制:根据响应类型和配置决定是否缓存响应结果。
二次封装axios步骤:
- 在项目src目录下新建一个api目录,用于存放axios请求相关的代码
- 新建src/api/request.js文件,对axios进行二次封装:
import axios from "axios"
const requests = axios.create({
baseURL: "https://192.168.5.98/mock",
timeout: 5000 // 设置超时时间,5S
})
// 请求拦截器:在发请求之前,请求拦截器可以检测到,可以在请求发出去之前做一些事情
requests.interceptors.request.use(
config => {
/*
这里可以添加公共请求头,如携带token(这里先不管token从哪里获取,假设已经定义了const token = ...;)
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
*/
return config;
},
error => { // 对请求错误做些什么
console.error('请求错误:', error);
Promise.reject(error);
}
)
// 响应拦截器
requests.interceptors.response.use(
res => { // 对响应数据做处理
if (res.status === 200) {
return Promise.resolve(res.data);
} else {
return Promise.reject(new Error('fail'));
}
},
error => { // 对响应错误做处理,例如判断状态码并展示错误信息
console.log('响应错误:', error);
if (error.response && error.response.status) {
switch (error.response.status) {
case 401:
break;
case 500:
console.log('服务器内部错误');
break;
default:
console.log('未知错误');
}
}
return Promise.reject(error);
},
)
export default requests
- 在src/main.js中全局导入并使用这个封装好的axios实例
import Vue from 'vue'
import App from './App.vue'
// 导入封装的axios
import requests from './api/request'
// 将requests挂载到Vue原型上,这样在所有Vue实例(包括组件)中都可以通过this.$http访问到
Vue.prototype.$http = requests
Vue.config.productionTip = false
new Vue({
render: h => h(App)
}).$mount('#app')
接下来就可以在组件中调用来发起http请求
<template>
<div>
<div id="app">
<button @click="getMsg">获取数据</button>
<p v-if="message">{{message}}</p>
</div>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
message: ''
}
},
methods: {
getMsg() {
this.$http.get('/example').then(res => {
console.log('请求成功', res);
this.message = res.data.message;
}).catch(err => {
console.error('请求失败', err);
});
}
}
}
</script>
<style>
</style>
4. API接口统一管理
创建src/api/index.js文件,在其中对api进行统一管理
import requests from './request.js'
export const getMessage = () => {
return requests({
url: '/example',
method: 'get'
})
}
然后对之前的组件代码进行修改
<template>
<div>
<div id="app">
<button @click="getMsg">获取数据</button>
<p v-if="message">{{message}}</p>
</div>
</div>
</template>
<script>
import { getMessage } from './api/index.js'
export default {
name: 'App',
data() {
return {
message: ''
}
},
methods: {
getMsg() {
getMessage().then(res => {
console.log('请求成功', res.data);
this.message = res.data.message;
}).catch(err => {
console.log('请求失败', err);
})
}
}
}
</script>
<style>
</style>
这里再说明一下,对于不同类型的请求以及包含参数是如何处理的。
/example/<id>
接口,接收GET
请求,需要在url中包含动态参数
export const getMessageById = (id) => {
return requests({
url: `/example/${id}`,
method: 'get'
})
}
/example
接口,接收POST
请求,携带参数:
export const createMessage = (messageData) => {
return requests({
url: '/example',
method: 'post',
data: messageData // 这里的messageData是你要传递给后端的数据
})
}
/example
接口,接收PUT
请求,携带参数且url包含动态参数:
export const updateMessage = (id, updatedData) => {
return requests({
url: `/example/${id}`,
method: 'put',
data: updatedData // 这里的updatedData是要更新的数据
})
}
/example
接口,接收GET
请求,url包含查询参数,如:http://ip:port/example?id=1&name=Tom
export const searchMessage = (params) => {
const url = `/example?id=${params.id}&name=${params.name}` // 根据实际参数构建URL
return requests({
url,
method: 'get'
})
}
// 推荐使用axios的params选项而不是手动拼接URL,以避免编码和特殊字符处理的问题
export const searchMessage = (params) => {
return requests({
url: '/example',
method: 'get',
params // axios会自动处理params对象并添加到URL查询字符串中
})
}