电商系统基于nuxt的axios封装代码分享

背景

在电商系统中,一些场景需要使用nuxt服务器端渲染技术,如首页、商品详情页等等,目的是为了弥补vue单页的seo的不足。

基于nuxt项目的api请求需要处理服务器端请求、客户端请求分离,权限拦截,token统一传递等逻辑,本文以javashop电商系统中的代码为例,分享相关经验。

一 先引入

首先创建一个resquest.js,这里面存放的是axios配置以及拦截器,最后导出一个axios对象

import Vue from 'vue'
import axios from 'axios'
import https from 'https'
import { Loading } from 'element-ui'
import { api } from '@/ui-domain'
import Storage from '@/utils/storage'
import checkToken from '@/utils/checkToken'
const qs = require('qs')

二 创建axios实例,并且添加默认的配置

const service = axios.create({
  timeout: 8000,     // 请求超时时间
  baseURL: api.buyer, // 后端API,用于在服务器端进行请求
  httpsAgent: new https.Agent({
    rejectUnauthorized: false
  }),
  paramsSerializer: params => qs.stringify(params, { arrayFormat: 'repeat' })
})

三 创建request拦截器

配置全屏加载,引入ElementUI库里面的loading;传递uuid,token配置

service.interceptors.request.use(config => {
  const { loading } = config
  // 如果是put/post请求,用qs.stringify序列化参数
  const is_put_post = config.method === 'put' || config.method === 'post' // 请求方式
  const is_json = config.headers['Content-Type'] === 'application/json' // 发送数据的格式
  const is_file = config.headers['Content-Type'] === 'multipart/form-data'// 发送数据的格式
  // 如果是put/post请求,用qs.stringify序列化参数
  if (is_put_post && is_json) {
    config.data = JSON.stringify(config.data)
  }
  if (is_put_post && !is_file && !is_json) {
    config.data = qs.stringify(config.data, { arrayFormat: 'repeat' })
  }
  /** 配置全屏加载 */
  // process.client 浏览器环境
  if (process.client && loading !== false) {
    config.loading = Loading.service({
      fullscreen: true,
      background: 'rgba(255,255,255,.3)',
      spinner: 'icon-custom-loading',
      lock: false
    })
  }
  // 如果是浏览器环境,请求头需要传递uuid
  if (process.client) {
    const uuid = Storage.getItem('uuid')
    config.headers['uuid'] = uuid
  } else {
    const { $store } = Vue.prototype.$nuxt
    const referer = $store.state.referer
    config.headers['Referer'] = referer || api.buyer
  }
  // 获取访问Token
  let accessToken = Storage.getItem('access_token')
  if (accessToken && config.needToken) {
    config.headers['Authorization'] = accessToken
  }
  return config
}, error => {
  Promise.reject(error)
})

四 创建response拦截器

service.interceptors.response.use(
  async response => {
    await closeLoading(response) // 关闭loading
    return response.data
  },
  // 错误处理
  async error => {
  // 如果是服务器端直接返回错误信息
    if (process.server) return Promise.reject(error)
    await closeLoading(error)
    const error_response = error.response || {}
    const error_data = error_response.data || {}
    // 状态码403登录状态以失效,移除tonken信息,返回登录页
    if (error_response.status === 403) {
      const { $store, $router, $route } = Vue.prototype.$nuxt
      if (!Storage.getItem('refresh_token')) return
      $store.dispatch('cart/cleanCartStoreAction')
      $store.dispatch('user/removeUserAction')
      $store.dispatch('user/removeAccessTokenAction')
      $store.dispatch('user/removeRefreshTokenAction')
      $router.push(`/login?forward=${$route.fullPath}`)
      return Promise.reject(error)
    }
    if (error.config.message !== false) {
      let _message = error.code === 'ECONNABORTED' ? '连接超时,请稍候再试!' : '网络错误,请稍后再试!'
      Vue.prototype.$message.error(error_data.message || _message)
    }
    return Promise.reject(error)
  }
)

五 关闭全局加载

Methodconst closeLoading = (target) => {
  if (!target.config || !target.config.loading) return true
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      target.config.loading.close()
      resolve()
    }, 200)
  })
}

六 导出Method

创建请求方法枚举字典,所有API的请求方法都在这个枚举字典中查找使用

export const Method = {
  GET: 'get',
  POST: 'post',
  PUT: 'put',
  DELETE: 'delete'
}

七 导出resquest

export default function request(options) {
  // 如果是服务端或者是请求的刷新token,不需要检查token直接请求。
  if (process.server || options.url.indexOf('passport/token') !== -1) {
    return service(options)
  }
  return new Promise((resolve, reject) => {
    checkToken(options).then(() => {
      service(options).then(resolve).catch(reject)
    })
  })
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kingapex1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值