vuecli4 + axios + mock

初始化vuecli项目

vue create my-app
cd my-app

yarn add -D less-loader@7.x less
yarn add element-ui vuex axios nprogress mockjs

vue add router

 

引入axios

src\util\util.js

/**
 * 表单序列化
 * @param {Object} data 请求参数
 */
export const serialize = data => {
  const list = []
  Object.keys(data).forEach(ele => {
    list.push(`${ele}=${data[ele]}`)
  })
  return list.join('&')
}

src\api\axios.js

import axios from 'axios'
import qs from 'qs'

import NProgress from 'nprogress'
import 'nprogress/nprogress.css'

import { Message } from 'element-ui'
import { serialize } from '@/util/util'
const { NODE_ENV } = process.env

if (NODE_ENV === 'production') {
  axios.defaults.baseURL = window.location.origin
}

// axios.defaults.timeout = 30000
// 返回其他状态吗
axios.defaults.validateStatus = function(status) {
  return status >= 200 && status <= 500 // 默认的
}
// 跨域请求,允许保存cookie
axios.defaults.withCredentials = true
NProgress.configure({
  showSpinner: false
})

/**
 * HTTPrequest拦截
 */
axios.interceptors.request.use(config => {
  NProgress.start() // start progress bar
  const { method, headers } = config

  const isToken = (config.headers || {}).isToken === false
  // 获取存储的token,若接口需要登录权限,则加上headers
  //const token = null
  //if (token && !isToken) {
    //config.headers.Authorization = 'Bearer ' + token // token
  //}

  // headers中配置serialize为true开启序列化
  if (method === 'post' && headers.serialize) {
    config.data = serialize(config.data)
    delete config.data.serialize
  }

  if (method === 'get') {
    config.paramsSerializer = function(params) {
      return qs.stringify(params, { arrayFormat: 'repeat' })
    }
  }

  return config
}, error => {
  return Promise.reject(error)
})

/**
 * HTTPresponse拦截
 */
axios.interceptors.response.use(res => {
  NProgress.done()
  const {
    data = {},
    status,
    statusText
  } = res
  var message = data.message || `${status} ${statusText}` || '未知错误'

  if (status !== 200) {
    Message.error(message)
    return Promise.reject(new Error(message))
  }

  const { code = 200 } = data
  if (code !== 200) {
    if (code === 401) {
      // 跳转到登录页面
    }
    Message.error(message)
    return Promise.reject(new Error(message))
  }
  
  return Promise.resolve(data.data)
}, err => {
  NProgress.done()
  Message.error(err)
  return Promise.reject(err)
})

export default axios

编写mock

mock\utils.js

/**
 * @param {string} url
 * @returns {Object}
 */
function param2Obj(url) {
  const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
  if (!search) {
    return {}
  }
  const obj = {}
  const searchArr = search.split('&')
  searchArr.forEach(v => {
    const index = v.indexOf('=')
    if (index !== -1) {
      const name = v.substring(0, index)
      const val = v.substring(index + 1, v.length)
      obj[name] = val
    }
  })
  return obj
}

/**
 * This is just a simple version of deep copy
 * Has a lot of edge cases bug
 * If you want to use a perfect deep copy, use lodash's _.cloneDeep
 * @param {Object} source
 * @returns {Object}
 */
function deepClone(source) {
  if (!source && typeof source !== 'object') {
    throw new Error('error arguments', 'deepClone')
  }
  const targetObj = source.constructor === Array ? [] : {}
  Object.keys(source).forEach(keys => {
    if (source[keys] && typeof source[keys] === 'object') {
      targetObj[keys] = deepClone(source[keys])
    } else {
      targetObj[keys] = source[keys]
    }
  })
  return targetObj
}

/**
 * 统一api返回结果
 */
class Respones {
  constructor(code = 200, message = null, data = null) {
    this.code = code // 状态码 200: 成功  401: 未登录
    this.message = message // 提示信息
    this.data = data // 返回结果
    // this.success = code === 200
  }

  static ok(data = null, message = null) {
    return new Respones(undefined, message, data)
  }

  static failed(message = '未知错误', data = null) {
    return new Respones(500, message, data)
  }
}

/**
 * 生成从min到max的随机整数
 * @param {Number} min 最小值
 * @param {Number} max 最大值
 */
function randomNum(min = 0, max = 100) {
  return Math.floor(Math.random() * (max - min + 1) + min)
}

module.exports = {
  param2Obj,
  deepClone,
  randomNum,
  Respones
}

mock\Login.js

const { Respones } = require('./utils')

module.exports = [
  {
    url: '/api/Login/Login\.*',
    type: 'get',
    response: () => {
      // const { query, params, body, headers } = config
      // const { cookie } = headers
      // console.log(query, params, body, cookie)
      return Respones.ok('登录成功')
    }
  },
  {
    url: '/api/Login/Logout\.*',
    type: 'get',
    response: () => {
      return Respones.ok('退出成功')
    }
  }
]

mock\entity\User.js

module.exports = {
  id: '@integer(1,10000000000000000000)',
  name: '@last()',
  pwd: '@string',
  realname: '@cname()',
  role: '@pick([0,1,100])',
  token: '@string'
}

mock\User.js

const { Respones, randomNum } = require('./utils')
const user = require('./entity/User')

module.exports = [
  {
    url: '/api/User/GetCurrentUser',
    type: 'get',
    response: () => {
      return Respones.ok({ user }.user)
    }
  },
  {
    url: '/api/User/GetUserList',
    type: 'get',
    response: () => {
      const list = []
      for (let i = 0; i < randomNum(1, 10); i++) {
        list.push({ user }.user)
      }
      return Respones.ok(list)
    }
  },
  {
    url: '/api/User/Add',
    type: 'post',
    response: ({ body }) => {
      return Respones.ok(Object.assign({}, { user }.user, body))
    }
  },
  {
    url: '/api/User/Delete\.*',
    type: 'get',
    response: ({ query }) => {
      if (!query.id) {
        return Respones.failed('请指定要删除的用户')
      }
      return Respones.ok(Object.assign({}, { user }.user, query))
    }
  }
]

mock\index.js

const Mock = require('mockjs')
const { param2Obj } = require('./utils')

const Login = require('./Login')
const User = require('./User')

const mocks = [
  ...Login,
  ...User
]

// for front mock
// please use it cautiously, it will redefine XMLHttpRequest,
// which will cause many of your third-party libraries to be invalidated(like progress event).
function mockXHR() {
  // mock patch
  // https://github.com/nuysoft/Mock/issues/300
  Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
  Mock.XHR.prototype.send = function() {
    if (this.custom.xhr) {
      this.custom.xhr.withCredentials = this.withCredentials || false

      if (this.responseType) {
        this.custom.xhr.responseType = this.responseType
      }
    }
    this.proxy_send(...arguments)
  }

  function XHR2ExpressReqWrap(respond) {
    return function(options) {
      let result = null
      if (respond instanceof Function) {
        const { body, type, url } = options
        // https://expressjs.com/en/4x/api.html#req
        result = respond({
          method: type,
          body: JSON.parse(body),
          query: param2Obj(url)
        })
      } else {
        result = respond
      }
      return Mock.mock(result)
    }
  }

  for (const i of mocks) {
    Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response))
  }
}

module.exports = {
  mocks,
  mockXHR
}

mock\mock-server.js

const chokidar = require('chokidar')
const bodyParser = require('body-parser')
const chalk = require('chalk')
const path = require('path')
const Mock = require('mockjs')

const mockDir = path.join(process.cwd(), 'mock')

function registerRoutes(app) {
  let mockLastIndex
  const { mocks } = require('./index.js')
  const mocksForServer = mocks.map(route => {
    return responseFake(route.url, route.type, route.response)
  })
  for (const mock of mocksForServer) {
    app[mock.type](mock.url, mock.response)
    mockLastIndex = app._router.stack.length
  }
  const mockRoutesLength = Object.keys(mocksForServer).length
  return {
    mockRoutesLength: mockRoutesLength,
    mockStartIndex: mockLastIndex - mockRoutesLength
  }
}

function unregisterRoutes() {
  Object.keys(require.cache).forEach(i => {
    if (i.includes(mockDir)) {
      delete require.cache[require.resolve(i)]
    }
  })
}

// for mock server
const responseFake = (url, type, respond) => {
  return {
    url: new RegExp(`${process.env.BASE_URL || ''}${url}`),
    type: type || 'get',
    response(req, res) {
      console.log('request invoke: ' + req.path)
      res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond))
    }
  }
}

module.exports = app => {
  // parse app.body
  // https://expressjs.com/en/4x/api.html#req.body
  app.use(bodyParser.json())
  app.use(bodyParser.urlencoded({
    extended: true
  }))

  const mockRoutes = registerRoutes(app)
  var mockRoutesLength = mockRoutes.mockRoutesLength
  var mockStartIndex = mockRoutes.mockStartIndex

  // watch files, hot reload mock server
  chokidar.watch(mockDir, {
    ignored: /mock-server/,
    ignoreInitial: true
  }).on('all', (event, path) => {
    if (event === 'change' || event === 'add') {
      try {
        // remove mock routes stack
        app._router.stack.splice(mockStartIndex, mockRoutesLength)

        // clear routes cache
        unregisterRoutes()

        const mockRoutes = registerRoutes(app)
        mockRoutesLength = mockRoutes.mockRoutesLength
        mockStartIndex = mockRoutes.mockStartIndex

        console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed  ${path}`))
      } catch (error) {
        console.log(chalk.redBright(error))
      }
    }
  })
}

vue.config.js

 

const config = {
  publicPath: process.env.VUE_APP_PUBLIC_PATH || '/',
  lintOnSave: process.env.NODE_ENV !== 'production',
  devServer: {
    proxy: process.env.NODE_ENV !== 'production' ? {
      '/api': {
        target: process.env.VUE_APP_URL,
        ws: false, // 需要websocket 开启
        pathRewrite: {
          '^/api': ''
        }
      }
    } : {}
  }
}

if (process.env.VUE_MOCK === 'true') {
  delete config.devServer.proxy
  config.devServer.before = require('./mock/mock-server.js')
}

module.exports = config

编写api

src\api\Login.js

import request from './axios'

/**
 * 用户(用户名+密码)登录
 * @param {String} name 用户名
 * @param {String} pwd 密码
 */
export const loginByUsername = (name, pwd) => {

  if (!name || !pwd) {
    return Promise.reject()
  }

  return request({
    url: '/api/Login/Login',
    method: 'get',
    headers: {
      isToken: false
      // 'Authorization': 'Basic dWx0cmFsYWI6Zm1hc3Rlcg=='
    },
    params: { name, pwd }
  })
}

/**
 * 退出登录
 */
export const logout = () => {
  return request({
    url: '/api/Login/Logout',
    method: 'get'
  })
}

src\api\User.js

import request from './axios'

/**
 * 获取当前登录用户信息
 */
export const getCurrentUser = () => {
  return request({
    url: '/api/User/GetCurrentUser',
    method: 'get'
  })
}

/**
 * 新增用户
 * @param {Object} data 用户对象
 * @param {String} data.realname 姓名
 * @param {String} data.name 账号
 * @param {String} data.pwd 密码
 * @param {Number} data.role 角色,默认1(学生)
 */
export const add = (data = {}) => {
  // return Promise.resolve(data)
  return request({
    url: '/api/User/Add',
    method: 'post',
    data
  })
}

/**
 * 删除用户
 * @param {String} id 用户ID,多个用户英文逗号隔开
 */
export const remove = (id) => {
  return request({
    url: '/api/User/Delete',
    method: 'get',
    params: {
      id
    }
  })
}

/**
 * 获取用户列表
 */
export const getList = () => {
  // return Promise.resolve([
  //   { id: 1, name: 'admin', realname: '管理员', role: 0 },
  //   { id: 2, name: 'teacher', realname: '老师', role: 0 },
  //   { id: 3, name: 'student', realname: '学生', role: 1 }
  // ])
  return request({
    url: '/api/User/GetUserList',
    method: 'get'
  })
}

api调用

import { getCurrentUser } from '@/api/User'

getCurrentUser()
      .then(res => {
           console.log(res)
      })
      .catch(err => {
           console.error(err )
      })

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值