uni-app Use uni.request package to send api request document server request navigation guard

foreword

  • When I first came into contact with uni-app, I thought about using axios to send the request directly. It can be sent successfully, but there is a problem with the request header.

  • Later, I found that the tutorials all use the @escookrequest-miniprogram three-party package to send requests - there is no problem

  • Why not send the request directly with uni.request(), because it is unreasonable to write and add the request header for each request

  • Later, with an in-depth understanding of uni-app, I found that open source frameworks, such as Ruoyi and Yudao, all encapsulate a layer of uni.request to send requests

  • Solved the problem of uniformly adding request headers. It is more reasonable to use uni.request. It may not be comprehensive to write it yourself, so you can directly move it

detail

1. Observe that we will find that there are two files upload.js and request.js under the utils tool folder when sending requests.

2. request.js adds request header and user id based on uni.request package. Specially used to send common api requests

3.upload.js adds request header and user id based on uni.uploadFile encapsulation, which is specially used to connect to the document server and upload image files

4. Not all interfaces need to add request headers, write isToken: false in the interface that does not need to add request headers,

Code

1. Create request.js and upload.js folders under the utils tool folder respectively - the code is as follows

request.js

// 引入vuex-调用退出登录方法
import store from '@/store'
// 引入基地址文件
import config from '@/config'
// 引入获取token文件
import { getAccessToken } from '@/utils/auth'
// 引入转台码错误文件
import errorCode from '@/utils/errorCode'
// 引入公共方法文件
import { toast, showConfirm, tansParams } from '@/utils/common'
let timeout = 10000
const baseUrl = config.baseUrl;
const request = config => {
  // 是否需要设置 token
  const isToken = (config.headers || {}).isToken === false
  config.header = config.header || {}
  if (getAccessToken() && !isToken) {
    config.header['Authorization'] = 'Bearer ' + getAccessToken()
  }
  // 设置租户 TODO 芋艿:强制 1 先
  config.header['tenant-id'] = '1';
  // get请求映射params参数
  if (config.params) {
    let url = config.url + '?' + tansParams(config.params)
    url = url.slice(0, -1)
    config.url = url
  }
  return new Promise((resolve, reject) => {
    uni.request({
        method: config.method || 'get',
        timeout: config.timeout ||  timeout,
        url: config.baseUrl || baseUrl + config.url,
        data: config.data,
        // header: config.header,
        header: config.header,
        dataType: 'json'
      }).then(response => {
        let [error, res] = response
        if (error) {
          toast('后端接口连接异常')
          reject('后端接口连接异常')
          return
        }
        const code = res.data.code || 200
        const msg = errorCode[code] || res.data.msg || errorCode['default']
        if (code === 401) {
          showConfirm('登录状态已过期,您可以继续留在该页面,或者重新登录?').then(res => {
            if (res.confirm) {
              store.dispatch('LogOut').then(res => {
                uni.reLaunch({ url: '/pages/login' })
              })
            }
          })
          reject('无效的会话,或者会话已过期,请重新登录。')
        } else if (code === 500) {
          toast(msg)
          reject('500')
        } else if (code !== 200) {
          toast(msg)
          reject(code)
        }
        resolve(res.data)
      })
      .catch(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) + '异常'
        }
        toast(message)
        reject(error)
      })
  })
}
export default request

upload.js

// 引入vuex-调用退出登录方法
import store from '@/store'
// 引入基地址文件
import config from '@/config'
// 引入获取token文件
import { getAccessToken } from '@/utils/auth'
// 引入转台码错误文件
import errorCode from '@/utils/errorCode'
// 引入公共方法文件
import { toast, showConfirm, tansParams } from '@/utils/common'
let timeout = 10000
const baseUrl = config.baseUrl
const upload = config => {
  // 是否需要设置 token
  const isToken = (config.headers || {}).isToken === false
  config.header = config.header || {}
  if (getAccessToken() && !isToken) {
    config.header['Authorization'] = 'Bearer ' + getAccessToken()
  }
  // get请求映射params参数
  if (config.params) {
    let url = config.url + '?' + tansParams(config.params)
    url = url.slice(0, -1)
    config.url = url
  }
  // 设置租户 TODO 芋艿:强制 1 先
  config.header['tenant-id'] = '1';
  return new Promise((resolve, reject) => {
      uni.uploadFile({
        timeout: config.timeout || timeout,
        url: baseUrl + config.url,
        filePath: config.filePath,
        name: config.name || 'file',
        header: config.header,
        formData: config.formData,
        method: config.method || 'post',
        success: (res) => {
          let result = JSON.parse(res.data)
          const code = result.code || 200
          const msg = errorCode[code] || result.msg || errorCode['default']
          if (code === 200) {
            resolve(result)
          } else if (code == 401) {
            showConfirm("登录状态已过期,您可以继续留在该页面,或者重新登录?").then(res => {
              if (res.confirm) {
                store.dispatch('LogOut').then(res => {
                  uni.reLaunch({ url: '/pages/login/login' })
                })
              }
            })
            reject('无效的会话,或者会话已过期,请重新登录。')
          } else if (code === 500) {
            toast(msg)
            reject('500')
          } else if (code !== 200) {
            toast(msg)
            reject(code)
          }
        },
        fail: (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) + '异常'
          }
          toast(message)
          reject(error)
        }
      })
  })
}
export default upload

2. Create the base address file config.js at the same level as utils.js in the outermost layer

// 应用全局配置
module.exports = {
  baseUrl: '基地址',
  // 应用信息
  appInfo: {
    // 应用名称
    name: "app",
    // 应用版本
    version: "1.0.0",
    // 应用logo
    logo: "/static/logo.png",
    // 官方网站
    site_url: "",
    // 政策协议
    agreements: [{
        title: "隐私政策",
        url: ""
      },
      {
        title: "用户服务协议",
        url: ""
      }
    ]
  }
}

3. Create auth.js file under the utils.js tool file - store token

RefreshTokenKey- is a non-inductive refresh form used to remedy token failure in exchange for token

const AccessTokenKey = 'ACCESS_TOKEN'
const RefreshTokenKey = 'REFRESH_TOKEN'
// ========== Token 相关 ==========
export function getAccessToken() {
  return uni.getStorageSync(AccessTokenKey)
}
export function getRefreshToken() {
  return uni.getStorageSync(RefreshTokenKey)
}
export function setToken(token) {
  uni.setStorageSync(AccessTokenKey, token.accessToken)
  uni.setStorageSync(RefreshTokenKey, token.refreshToken)
}
export function removeToken() {
  uni.removeStorageSync(AccessTokenKey)
  uni.removeStorageSync(RefreshTokenKey)
}

4. Create the errorCode.js file under the utils.js tool file - status code error file

export default {
  '401': '认证失败,无法访问系统资源',
  '403': '当前操作没有权限',
  '404': '访问资源不存在',
  'default': '系统未知错误,请反馈给管理员'
}

5. Create a common.js file under the utils.js tool file - public method

/**
* 显示消息提示框
* @param content 提示的标题
*/
export function toast(content) {
  uni.showToast({
    icon: 'none',
    title: content
  })
}
/**
* 显示模态弹窗
* @param content 提示的标题
*/
export function showConfirm(content) {
  return new Promise((resolve, reject) => {
    uni.showModal({
      title: '提示',
      content: content,
      cancelText: '取消',
      confirmText: '确定',
      success: function(res) {
        resolve(res)
      }
    })
  })
}
/**
* 参数处理
* @param params 参数
*/
export function tansParams(params) {
  let result = ''
  for (const propName of Object.keys(params)) {
    const value = params[propName]
    var part = encodeURIComponent(propName) + "="
    if (value !== null && value !== "" && typeof (value) !== "undefined") {
      if (typeof value === 'object') {
        for (const key of Object.keys(value)) {
          if (value[key] !== null && value[key] !== "" && typeof (value[key]) !== 'undefined') {
            let params = propName + '[' + key + ']'
            var subPart = encodeURIComponent(params) + "="
            result += subPart + encodeURIComponent(value[key]) + "&"
          }
        }
      } else {
        result += part + encodeURIComponent(value) + "&"
      }
    }
  }
  return result
}

5. Create a permission.js file under the utils.js tool file - navigation guard setting whitelist, page blocker

import { getAccessToken } from '@/utils/auth'
// 登录页面
const loginPage = "/pages/login"
// 页面白名单
const whiteList = [
  '/pages/login', '/pages/common/webview/index'
]
// 检查地址白名单
function checkWhite(url) {
  const path = url.split('?')[0]
  return whiteList.indexOf(path) !== -1
}
// 页面跳转验证拦截器
let list = ["navigateTo", "redirectTo", "reLaunch", "switchTab"]
list.forEach(item => {
  uni.addInterceptor(item, {
    invoke(to) {
      if (getAccessToken()) {
        if (to.path === loginPage) {
          uni.reLaunch({ url: "/" })
        }
        return true
      } else {
        if (checkWhite(to.url)) {
          return true
        }
        uni.reLaunch({ url: loginPage })
        return false
      }
    },
    fail(err) {
      console.log(err)
    }
  })
})

6. Introduce the navigation guard file in main.js

// permission
// 导航守卫文件
import './permission' 

7. Send request example

// 对接文档服务器封装
import upload from '@/utils/upload'
// 对接普通api接口
import request from '@/utils/request'
// 登录方法-不需要添加token-请求头添加isToken: false
export function login(username, password, captchaVerification) {
    const data = {
        username,
        password,
        captchaVerification
    }
    return request({
        url: '/system/auth/login',
        headers: {
            isToken: false
        },
        'method': 'POST',
        'data': data
    })
}
// 查询用户个人信息-普通api添加token+用户id
export function getUserProfile() {
  return request({
    url: '/system/user/profile/get',
    method: 'GET'
  })
}
// 用户头像上传-对接文档服务器
export function uploadAvatar(data) {
  return upload({
    url: '/system/user/profile/update-avatar',
    method: 'PUT',
    name: data.name,
    filePath: data.filePath
  })
}

Summarize:

After this process, I believe you have a preliminary deep impression on uni-app using uni.request package to send api request document server request navigation guard, but the situation we encounter in actual development must be different, so We need to understand its principle, and it is always the same. Come on, hit the workers!

Please point out any deficiencies, thank you -- Fengguowuhen

Guess you like

Origin blog.csdn.net/weixin_53579656/article/details/131905315