axios请求封装与开发环境proxyTable代理

一、axios请求封装

1. axios安装与使用

1.1 安装

 npm install axios; // 安装axios

1.2 引入

在项目中 axios 的封装一般都放在 src 目录下的 utils 文件夹中,因此我们在此处新建一个 request.js 文件用来封装我们的 axios 请求。先贴代码:

/****   request.js   ****/
// 导入axios
import axios from 'axios'
// 使用element-ui Message做消息提醒
import { Message} from 'element-ui';
// 1. 创建新的axios实例,
const service = axios.create({
  // 公共接口--这里注意后面会讲
  baseURL: process.env.BASE_API,
  // 超时时间 单位是ms,这里设置了3s的超时时间
  timeout: 3 * 1000
})
// 2.请求拦截器
service.interceptors.request.use(config => {
  // 发请求前做的一些处理,数据转化,配置请求头,设置token,设置loading等,根据需求去添加
   config.data = JSON.stringify(config.data); //数据转化,也可以使用qs转换
   config.headers = {
     'Content-Type':'application/x-www-form-urlencoded' //配置请求头
   }
   // 注意使用token的时候需要引入cookie方法或者用本地localStorage等方法,推荐js-cookie
   const token = getCookie('名称'); //这里取token之前,你肯定需要先拿到token,存一下
   if(token){
      config.params = {'token':token} //如果要求携带在参数中
      config.headers.token = token; //如果要求携带在请求头中
    }
  return config
}, error => {
  Promise.reject(error)
})

// 3.响应拦截器
service.interceptors.response.use(res => {
    // 未设置状态码则默认成功状态
    const code = res.data.code || 200;
    // 获取错误信息
    const msg = errorCode[code] || res.data.msg || errorCode['default']
    if (msg == 401 ) {
      MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', {
          confirmButtonText: '重新登录',
          cancelButtonText: '取消',
          type: 'warning'
        }
      ).then(() => {
        store.dispatch('LogOut').then(() => {
          location.href = '/';
        })
      }).catch(() => {});
    } else if (code === 500) {
      Message({
        message: msg,
        type: 'error'
      })
      return Promise.reject(new Error(msg))
    } else if (code !== 200) {
      Notification.error({
        title: msg
      })
      return Promise.reject('error')
    } else {
      return res.data
    }
  },
  error => {
    console.log('err' + error)
    let { message } = error;
    if (message == "Network Error") {
      message = "后端接口连接异常";
    }
    else if (message.includes("timeout")) {
      message = "系统接口请求超时";
    }
    else if (message.includes("Request failed with status code")) {
      message = "系统接口" + message.substr(message.length - 3) + "异常";
    }
    Message({
      message: message,
      type: 'error',
      duration: 5 * 1000
    })
    return Promise.reject(error)
  }
)
// 4.导出文件
export default service

1.3 环境切换

       我们的项目环境可能有开发环境、测试环境和生产环境。我么可以通过node的环境变量来匹配我们的默认的接口url前缀。
在这里要注意的是 axios.defaults.baseURL 可以设置 axios 的默认请求地址。

// 设置baseURL方法一:外部设置
if (process.env.NODE_ENV == 'development') {    
    axios.defaults.baseURL = 'https://www.baidu.com';} 
else if (process.env.NODE_ENV == 'production') {    
    axios.defaults.baseURL = 'https://www.production.com';
}
// 设置baseURL方法二:实例内设置
const service = axios.create({
  // baseURL: process.env.NODE_ENV == 'development' ? 'https://www.baidu.com' : 'https://www.production.com'
  timeout: 3 * 1000
})
// 以上两种方法是等价的,任选一种都可以

1.4 设置请求超时

通过axios.defaults.timeout设置默认的请求超时时间。

1.5 请求头设置

由于post请求时需要加上内容的数据类型,因此需要加上请求头配置

axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';

1.6 请求拦截

我们在发送请求前可以进行请求拦截。当系统需要登录时,在这里可以判断 token 的状态,若存在则将 token 加入请求头中。

service.interceptors.request.use(config => {
  //发请求前做的一些处理,数据转化,配置请求头,设置token,设置loading等,根据需求去添加
   config.data = JSON.stringify(config.data); //数据转化,也可以使用qs转换
   config.headers = {
     'Content-Type':'application/json;charset=UTF-8' //配置请求头
   }
   //注意使用token的时候需要引入cookie方法或者用本地localStorage等方法,推荐js-cookie
   const token = getCookie('名称');//这里取token之前,你肯定需要先拿到token,存一下
   if(token){
      config.params = {'token':token} //如果要求携带在参数中
      config.headers.token= token; //如果要求携带在请求头中
    }
  return config
}, error => {
  Promise.reject(error)
})

1.7 响应拦截

       响应拦截器就是当服务器返回给我们的数据,我们可以在拿到之前对它进行一些处理。例如,当状态码为除 200 外的其他码时则根据状态码类型进行一些我们需要的错误提示,我们还可以在这里对执行未登陆或登录过期后跳转登录页的操作。

service.interceptors.response.use(res => {
    // 未设置状态码则默认成功状态
    const code = res.data.code || 200;
    // 获取错误信息
    const msg = errorCode[code] || res.data.msg || errorCode['default']
    if (msg == 401 ) {
      MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', {
          confirmButtonText: '重新登录',
          cancelButtonText: '取消',
          type: 'warning'
        }
      ).then(() => {
        store.dispatch('LogOut').then(() => {
          location.href = '/';
        })
      }).catch(() => {});
    } else if (code === 500) {
      Message({
        message: msg,
        type: 'error'
      })
      return Promise.reject(new Error(msg))
    } else if (code !== 200) {
      Notification.error({
        title: msg
      })
      return Promise.reject('error')
    } else {
      return res.data
    }
  },
  error => {
    console.log('err' + error)
    let { message } = error;
    if (message == "Network Error") {
      message = "后端接口连接异常";
    }
    else if (message.includes("timeout")) {
      message = "系统接口请求超时";
    }
    else if (message.includes("Request failed with status code")) {
      message = "系统接口" + message.substr(message.length - 3) + "异常";
    }
    Message({
      message: message,
      type: 'error',
      duration: 5 * 1000
    })
    return Promise.reject(error)
  }
)

1.8 使用方法

       请求方法都会放在 src 目录下的 api 文件夹中统一管理。当项目规模较小时直接创建一个 api.js,将所有的请求放在其中即可,当项目规模较大时可根据模块和功能进行划分,将请求置于多个文件内进行管理。

/****     api.js     ****/
import request from '@/utils/request'

// 获取验证码图片
export function getCodeImg() {
  return request({
    url: '/auditms/captchaImage',
    method: 'get'
  })
}

// 登录方法
export function login(data) {
  return request({
    url: '/auditms/api/account/login',
    method: 'post',
    data: data
  })
}

2. axios二次封装

       我们常用的请求方式有 getpostputdelete,尤其是 getpost,相信大家一定都不陌生,axios 也有响应的方法。当项目请求数量比较多时我们可将 axios 进行二次封装

2.1 封装方法

axios 的二次封装也放在 src 目录下的 utils 文件夹中,我们在此处新建一个http.js 的文件。代码如下:

/****     http.js     ****/
import request from './request.js'

const http = {
  /**
   * methods: 请求
   * @param url 请求地址 
   * @param params 请求参数
   */
  get(url, params) {
    const config = {
      method: 'get',
      url: url,
    }
    if(params)
      config.params = params;
    return request(config)
  },
  post(url, params) {
    const config = {
      method: 'post',
      url: url,
    }
    if(params) 
      config.data = params;
    return request(config)
  },
  put(url, params) {
    const config = {
      method: 'put',
      url: url,
    }
    if(params)
      config.params = params;
    return request(config)
  },
  delete(url, params) {
    const config = {
      method: 'delete',
      url: url,
    }
    if(params)
      config.params = params;
    return request(config)
  }
}

export default http

3.2 使用方法

封装后按如下格式即可使用。

/****     api.js     ****/
import http from '@/utils/http'

// 获取步骤条
export function getStepTitle() {
  return http.get(`/deploy/separate/stepTitle`)
}

// 上传网络配置信息
export function netWorkMgr(params) {
  return http.post(`/deploy/separate/netWorkMgr`, params)
}

二、开发环境proxyTable代理详解

       前面讲完 axios 的安装、封装和使用,后面就讲讲项目前后端分离时开发环境如何解决跨域问题

1. proxyTable原理概述

       我们在使用 vue-cli 工具生成 vue 项目时,生成的项目里有一个 config 文件夹,里面会有一个 index.js
文件。文件内容如下,老规矩,与文章无关的内容先省略。

'use strict'
const path = require('path')

module.exports = {
  // 开发相关配置
  dev: {
    // Paths
    assetsSubDirectory: 'static', //子目录,一般存放css,js,image等文件
    assetsPublicPath: '/', //根目录
    proxyTable: {},
    // 省略部分内容
  },
  // 与编译相关的配置
  build: {
  // 省略
  }
}

       其中的 proxyTable 空节点是 vue-cli 脚手架在开发模式下为我们提供的一个代理服务器服务

       当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域,但由于项目前后端分离,现在开发过程中跨域是无可避免的。

       proxyTable 的核心就是将服务器端(另一个域)代理到开发环境的域,也就是将服务器端代理到开发环境的node站点。

       也正因如此,我们用F12查看网络时,请求的URl就是当前页面的URL,因为我们代理的结果就是发送到开发环境(也就是当前环境)的node站点。

2. 使用方法

       讲完了 proxyTable 的原理,接下来就讲讲它的使用。

       首先,使用 proxyTable 跨域有三个文件需要注意,这三个文件分别是 src -> api -> api.js(查看请求URL)、src -> utils -> request.js(查看axios的baseURL配置)和 config -> index.js

以上面的获取验证码请求为例:

export function getCodeImg() {
  return request({
    url: '/auditms/captchaImage',
    method: 'get'
  })
}

请求的url为 /auditms/captchaImage

再看 request.js 中的baseURL配置:

const service = axios.create({
  // axios中请求配置有baseURL选项,表示请求URL公共部分
  // baseURL: process.env.BASE_API,
  // 超时
  timeout: 10000,
})

baseURL 未曾配置,也就是说此时请求地址为 /auditms/captchaImage

       此处需注意:若这两个URL拼接起来后是一个带有协议、域名、端口号的绝对地址或是请求中的URL直接就是绝对地址那么该请求就不会走 proxyTable 代理。

最后,我们再仔细看看 config -> index.js 文件中的 proxyTable 节点配置。

proxyTable: { //可利用该属性解决跨域的问题
  // 1、匹配请求
  '/auditms': {
    // 2、服务地址
    target: 'http://127.0.0.1:3000',
    // 3、证书安全
    // secure: true, //如果是 https ,需要开启这个选项
    changeOrigin: true, //是否是跨域请求?肯定是啊,不跨域就没有必要配置这个proxyTable了.
    // 4、路径重写
    pathRewrite: {
      '^/auditms': '/auditms',
    }
  },
},

       我们要关注的第一个地方是匹配规则,也就是上面代码中的第三行:'/auditms:',这个地方就是请求进行匹配的地方,匹配上的请求会被转发到对应的服务。而请求匹配的规则就一点:先到先得

'/aaa/bb': {
  target: 'xxx',
  prependPath: true,
  changeOrigin: true,
  secure: false
 },
 '/aaa/bb/cccccc': {
  target: 'xxx',
  prependPath: true,
  changeOrigin: true,
  secure: false
 },

假设设置了以上两个代理,当请求URL为 /aaa/bb/ccccc/dd 时,请求会被第一个代理转发到相应的服务上,哪怕后面的更为精确。
因此,我们在写匹配规则的时候要将最严格的匹配模式放在最前面,将不严格的方式放在后面。

       我们要关注的第二个地方就是服务地址,匹配上的请求会发往相应的服务地址,如上面的验证码请求就将被发往 http://127.0.0.1:3000/auditms/captchaImage

       我们要关注的第三个地方是 secure 配置,当服务地址的协议为 https 时需要开启此选项。我在项目开发时因为将此项设置为 secure: true,花了我半天的时间才找到问题所在,但我并不了解其中原理,若以后大家确定自己其他地方都已配置正确时可更改此项为 secure: false 试试。

       终于到最后一点啦,路径重写,顾名思义,就是将前面匹配的路径进行重写。如前面的例子中就是将 /auditms 重写为 /auditms ,有的人可能会想,这不是啥也没做吗?没错,此处就是啥也没做,这种情况下就可以将 pathRewrite 配置注释掉。

pathRewrite: {
  '^/auditms': '/auditms',
}

       如果一个项目中出现多个后端服务地址时我们就会用到此配置,通过设置不同的URL前缀来控制请求发往不同的服务,当我们在请求URL前加入了语义化的前缀时也可通过设置值为空串来删掉无用的URL前缀。

终于写完啦,下班回家咯,希望这篇文章能对大家有所帮助。不卷了,溜了溜了。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值