欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

前后端联调的规范(初级)

程序员文章站 2022-06-03 21:27:20
...
  1. 后端返回的状态
    (1) -404/-500/-201/-403 等错误
    (2) 网络/超时 等错误
    (3) 返回 因为参数类型或者必传参数没传 等常规性错误

  2. 一般错误处理
    在axios的封装函数中拦截

  axios.interceptors.response.use(res => {
    // p2常规性错误捕获
  }, err => {
    // p1错误捕获
    // err.response.status 
    // 200 成功
    // 300 重定向
    // 400 请求错误
    // 500 服务器错误
  })

如何更好的对axios进行拦截处理

axios拦截的作用

  1. 设定默认的url前辍

  2. 设定header请求头参数

  3. 添加token以及公共参数

  4. 对错误处理进行拦截

  5. 默认url前辍

  axios.defaults.baseURL = process.env.VUE_APP_BASE_URL

其中VUE_APP_BASE_URL参数配合package.json配置环境

  1. 设置header请求头参数
  axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8';
  1. 添加token以及公共参数
  axios.interceptors.request.use(config => {
    if (window.localStorage.getItem('token')){
      config.headers.common['Authorization'] = window.localStorage.getItem('token');
    }
  })
  1. 对错误处理进行拦截
  axios.interceptors.response.use(res => {
    if(res.status === 201) {
      ...
    }
    return Promise.resolve(res.data);
  }, err => {
    if (error.response && error.response.status >= 500){
      ...
    }
    return Promise.resolve(res.data);
  })

完整代码

import axios from 'axios'
import Router from '@/router/index'

// 封装的本地存储类
class Db {
  constructor(status = 1, scope = 'anlin') {
    if (typeof status !== 'number' || typeof scope !== 'string') {
      alert('传入的参数格式不正确,将使用默认的参数配置')
      this.scope = 'anlin'
      this.status = 1
    } else {
      this.scope = scope
      this.status = status
    }
  }
  setItem (key, value, item) {
    item.setItem(this.scope + '_' + key, JSON.stringify(value))
  }
  set (key, value) {
    if (this.status === 1) {
      this.setItem(key, value, localStorage)
    } else {
      this.setItem(key, value, sessionStorage)
    }
  }
  getItem (key, item) {
    try {
      return JSON.parse(item.getItem(this.scope + '_' + key))
    } catch {
      return null
    }
  }
  get (key) {
    if (this.status === 1) {
      return this.getItem(key, localStorage)
    } else {
      return this.getItem(key, sessionStorage)
    }
  }
  clearItem (item) {
    for (const key in item) {
      if (key.indexOf(this.scope) !== -1) {
        item.removeItem(key)
      }
    }
  }
  clear () {
    if (this.status === 1) {
      this.clearItem(localStorage)
    } else {
      this.clearItem(sessionStorage)
    }
  }
  removeItem (key, item) {
    item.removeItem(this.scope + '_' + key)
  }
  remove (key) {
    if (this.status === 1) {
      this.removeItem(key, localStorage)
    } else {
      this.removeItem(key, sessionStorage)
    }
  }
}
const loc = new Db()

// 模拟浏览器的缓存数据,用来测试
loc.set('id', '1')
loc.set('token', 'abcdefg')

// 判断传入的数据类型
const verType = data => {
  const dataType = Object.prototype.toString.call(data)
  return dataType.split(" ")[1].replace(']', '')
}

// 设定axios初始化
axios.defaults.baseURL = process.env.VUE_APP_BASE_URL
axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8'

// 导出函数,当调用函数的时候,设定axios的拦截器并返回axios
export default () => {
  // 发起请求的时候拦截
  axios.interceptors.request.use(config => { 
    const {data, headers} = config  
    // 如果存在token,则在请求头带上参数
    const token = loc.get('token')
    token && (headers.common['Authorization'] = token)

    // 如果config包含data
    if (data){
      // 则增加公共参数
      const id = loc.get('id')
      id && (data.id = id)       
      // 如果config.data存在undefined,则把对应的属性删除
      if (verType(data) === 'Object'){
        const keyArr= Object.keys(data)
        for(let i of keyArr) {
          if(data[i] === undefined) {
            delete data[i]
          }
        }
      }  
    }
    return config;
  }, err => {
    return Promise.reject(err);
  })

  axios.interceptors.response.use(res => {
    // 如果后端返回的状态为201, 表示权限不够
    if (res.status === 201){
      // 清空浏览器缓存数据,并跳转到首页(登陆页)
      loc.clear()
      Router.push('/')
    }
    return Promise.resolve(res.data);
  }, err => {
    const response = err.response
    if (response && response.status >= 500) {
      alert('服务器错误')
    }
    if (response && response.status === 404) {
      alert('接口不存在')
    }
    return Promise.reject(err);
  });
  return axios;
}
  1. 避免出现服务器错误
    后端验证
  2. 参数 -> 类型和必有字段验证
  // 传入一个数组,数组中对象进行undefined和类型的判断
  const checkUndefined = (arr) => {
    let flog = true;
    for (let i of arr) {
      if (i[i.label] === undefined) {
        flog = false
        break;
      } else {
        if (typeof i[i.label] !== i.type) {
          flog = false
          break;
        }
      }
    }
    return flog;
  }
  router.post('/note', async ctx => {
    const { user, title, content } = ctx.request.body;
    const verFlog = checkUndefined([
      {user: user,type: 'string',label: 'user'},
      {title: title,type: 'string',label: 'title'},
      {content: content,type: 'string',label: 'content'},
    ]);
    if (verFlog) {...} else {...}
  })
  1. 超时处理 -> 返回对应的数据
  ctx.body = await Note.find(findObj).limit(skip).skip(skip - limit).then(async res => {
    let length = await Note.find({ user }).count()
    return {
      code: 0,
      msg: '查询成功',
      data: res,
      total: length
    }
  }).catch(err => {
    // 疑问1: 如果await.find... 的处理超时,这里会被捕获吗? 如果会,超时的时间是多久?
    // 如果这里不能捕获超时的话,需要使用定时器来处理
    return util.back(500)
  })
  1. 代码错误 -> 异常捕获 -> 返回对应的数据
  ctx.body = await Note.find(findObj).limit(skip).skip(skip - limit).then(async res => {
    let length 
    try{
      let length = await Note.find({ user }).count()
    }catch{
      let length = 0
    }      
    return {
      code: 0,
      msg: '查询成功',
      data: res,
      total: length
    }
  }).catch(err => {
    return util.back(500)
  })