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请求之前执行。其主要作用包括但不限于:

  1. 统一添加请求头:如为所有请求自动添加认证Token、API版本号、用户标识等公共信息。
  2. 格式化请求数据:在发送请求前对请求体进行预处理或转换。
  3. 请求异常处理:在请求发送前进行条件检查,如若不符合条件则阻止请求发出。
  4. 请求缓存控制:根据特定条件决定是否从缓存中获取数据而非向服务器发送请求。

响应拦截器:响应拦截器在收到HTTP响应后、响应数据传递给请求回调之前执行。它的用途主要包括:

  1. 统一错误处理:对HTTP状态码进行判断,针对不同响应码执行相应的逻辑,如处理API错误码,统一弹框提示等。
  2. 数据格式化:对接收到的数据进行预处理或转换,如对JSON数据进行解析或进一步加工。
  3. 身份验证失败处理:如检测到401 Unauthorized状态码,自动跳转至登录页面或清除用户的授权信息。
  4. 响应缓存控制:根据响应类型和配置决定是否缓存响应结果。

二次封装axios步骤:
  1. 在项目src目录下新建一个api目录,用于存放axios请求相关的代码
  2. 新建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
  1. 在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查询字符串中
  })
}
posted @ 2024-03-27 14:39  Charramma  阅读(332)  评论(0编辑  收藏  举报