前端渣渣对requestAPI的不断重构之路

前言

📢 感兴趣的能够去看看阿宽的博客javascript

我仍是自我介绍一下吧,本人 19届毕业生,在大二的时候自学前端,没有系统的学习,也没人带,从菜鸟教程那里去学 html 、css 、js 等,而后中间去写过一点 php,也是 CURD 的工做。php

自学路上太艰难,由于不只仅会遇到一些除了前端的问题,还会遇到许多其余没涉及到的问题,那时候的本身属于,这个东西能作出来就好了,不会去考虑优化,或者重构代码等,直到大三去实习了一段时间以后,才发现本身多菜,乃至如今毕业了,入部门直接作一些重要的需求,如 xx 展会演示的某个功能,看着前人代码,越感本身菜到极致。css

好了,不扯那么多了,上边是为了作铺垫,由于这篇文章,会有我最初的代码风格和如今的一个风格。html

功能

这里就以一个最简单的功能进行讲解,一个输入框,输入用户名和密码,而后点击登陆,就登陆完成啦 ~前端

登陆成功以后,拿到用户信息 ~vue

最初的样子

在我年少无知的时候,jQuery 就是爸爸,有他在,没什么作不到的,可是说实在话,那时候真的用 jQuery 就只是为了 ajax 发送请求,因而个人代码是这样的java

// adapter.js
$.ajax({
  url: 'http://backend-dev-manage/login',
  method: 'post',
  dataType: 'json',
  data: {
    username: 'pengdaokuan',
    password: '123456'
  },
  success: function(data) {
    console.log(data)
  }
})
复制代码

👍perfect ! 就很棒 ~react

按道理来说,是没得问题的,可是这时候,我身份就变了,就是...我成为了搬运工 ...jquery

为何这么说,由于每次要发送请求,我都要 copy 代码,ctrl + cctrl + v 了解一下 ...ios

哪一个页面须要发请求,我直接一顿操做,copy 就完事了

// a.html
$.ajax({
  url: 'http://backend-dev-manage/getAllStudent',
  method: 'get',
  success: function(data) {
    console.log(data)
  }
})

// b.html
$.ajax({
  url: 'http://backend-dev-manage/getAllTeacher',
  method: 'get',
  success: function(data) {
    console.log(data)
  }
})

// c.html
$.ajax({
  url: 'http://backend-dev-manage/getAllManage',
  method: 'get',
  success: function(data) {
    console.log(data)
  }
})
复制代码

你没看错,我就是这么操做的,一直到去年大三实习前,仍是这种操做,可是!在看了一些别人代码以后,我,长大了...

实习的成长

在实习的时候,看到上一个实习生写的代码,我也试着改了一下。因而,代码成这样了

// adapter.js
import $ from 'jquery'

export default function requestJQuery(url, method, data) {
  return new Promise((resolve, reject) => {
    $.ajax({
      url: url,
      method: method || 'GET',
      data: data,
      success: function(data) {
        resolve(data)
      },
      error: function(error) {
        reject(error)
      }
    })
  })
}
复制代码

在请求的地方我引入这个 requestJQuery 就完事了嘛,这样就不用继续 copy 了,我可真是个小机灵鬼

你觉得这就完了嘛,不存在的,在我看了 ant-design-pro 对于 request 的这段代码以后,我枯了... 我果真仍是菜啊...

借鉴别人的代码

这时候从 jQuery 变成了 axios,因而代码成了这样,90%借鉴 ant-design-pro

果粒橙有 5%果粒也叫果粒橙,个人代码中有 10%的 bug,这也是个人代码

// adapter.js

import axios from 'axios'

const codeMessage = {
  200: '服务器成功返回请求的数据。',
  201: '新建或修改数据成功。',
  202: '一个请求已经进入后台排队(异步任务)。',
  204: '删除数据成功。',
  400: '发出的请求有错误,服务器没有进行新建或修改数据的操做。',
  401: '用户没有权限(令牌、用户名、密码错误)。',
  403: '用户获得受权,可是访问是被禁止的。',
  404: '发出的请求针对的是不存在的记录,服务器没有进行操做。',
  406: '请求的格式不可得。',
  410: '请求的资源被永久删除,且不会再获得的。',
  422: '当建立一个对象时,发生一个验证错误。',
  500: '服务器发生错误,请检查服务器。',
  502: '网关错误。',
  503: '服务不可用,服务器暂时过载或维护。',
  504: '网关超时。'
}

// 检查http code
const checkStatus = response => {
  if (response.status >= 200 && response.status < 300) {
    return response
  }
  const errortext = codeMessage[response.status] || response.statusText
  // 弹窗通知报错
  const error = new Error(errortext)
  error.name = response.status
  error.response = response
  throw error
}

/** * 封装的请求函数 * @param {string} url * @param {object} [option] * @return {object} */
export default function request(option) {
  const newOptions = Object.assign({}, option, {
    credentials: 'include'
  })
  
  if (
    newOptions.method === 'POST' ||
    newOptions.method === 'PUT' ||
    newOptions.method === 'DELETE'
  ) {
    if (!(newOptions.body instanceof FormData)) {
      newOptions.headers = {
        Accept: 'application/json',
        'Content-Type': 'application/json; charset=utf-8',
        ...newOptions.headers
      }
      newOptions.data = JSON.parse(JSON.stringify(newOptions.data))
    } else {
      newOptions.headers = {
        Accept: 'application/json',
        ...newOptions.headers
      }
    }
  } else {
    newOptions.headers = {
      Accept: 'application/json',
      ...newOptions.headers
    }
  }

  return axios(newOptions)
    .then(checkStatus)
    .then(response => {
      var res = response.data
      if (res.code === 1) {
        return res.data
      } else {
        Message.error({
          content: res.msg,
          duration: 1.5
        })
      }
    })
    .catch(err => {
      let status = err.name
      if (status === 401) {
        console.log('未经受权, 错误码:', status)
      }
      if (status === 403) {
        console.log('禁止访问, 错误码:', status)
      }
      if (status <= 504 && status >= 500) {
        console.log('服务器错误, 错误码:', status)
      }
      if (status >= 404 && status < 422) {
        console.log('找不到资源路径, 错误码 :', status)
      }
    })
}
复制代码

“ 💬 这个代码不错,只是长得有点像 ant-design-pro ”

看到这,你觉得完了吗,no no no,上边的代码仍是太乱了,而后呢,我看了组里的项目,对 request 的调用,又上升到了一个层级

重构一下

最近看了组里边对 request 的处理, 以为很用帮助, 最起码对我来讲, 又刷新了个人见解, 因而借鉴了前人的代码, 再加上本身以前对 ant-design-pro 的理解, 从新写了一遍, 而且将一些常量、方法抽了出去,看一下代码

/** * @param {String} actionName 请求的名称 * @param {Object} options * @param {Boolean} needAuthorToken 是否须要token,默认不须要 * @param {Boolean} needCsrfToken 是否须要csrfToken,默认不须要 */
import axios from 'axios'
import Cookies from 'js-cookie'
import { handleUrl, handleHttpStatus, handleResultStatus } from './utils'

class Adapter {
  // 获取options
  getOptions = ({ options, needAuthorToken, needCsrfToken }) => {
    let { url, headers } = options
    // 检查url,url可能为 /api/backend/,也多是完整的url=http://seewo.com
    url = handleUrl(url) 
    if (needAuthorToken) {
      const authorToken = Cookies.get('x-auth-token') // 这个由大家定义
      headers['xauthtoken'] = authorToken
    }
    if (needCsrfToken) {
      const csrfToken = Cookies.get('csrfToken') // 这个由大家定义
      headers['x-csrf-token'] = csrfToken
    }
    return Object.assign(options, {
      url: url,
      method: options.method || 'GET',
      headers: headers
    })
  }

  // request
  dispatchCallAPI = ({ options, authorToken = false, csrfToken = false }) => {
    const options = this.getOptions({ options, authorToken, csrfToken })

    return axios(options)
      .then(handleHttpStatus)
      .then(handleResultStatus)
      .then(res => {
        /** * 若是返回的不是一个JSON对象,而是一个字符串,所以须要对这个字符串进行处理 * 若是直接返回的是一个JSON对象,这个时候,JSON.parse会抛出异常,若是出现异常 * 咱们直接返回这个对象自己的值便可 */
        try {
          return JSON.parse(res.data)
        } catch (err) {
          return res.data
        }
      })
      .catch(error => {
        console.log(error)
      })
  }
}

export default new Adapter()
复制代码
import React from 'react'
import adapter from './adapter'

export class requestComponent extends React.PureComponent {
  componentWillMount() {
    // 发送请求
    adapter
      .requestCallAPI({
        url: '/erek-vue-manage/user/retriveList',
        headers: { 'Content-Type': 'application/json; charset=utf-8' }
      })
      .then(res => {
        console.log(res)
      })
      .catch(err => {
        console.log(err)
      })
  }
}
复制代码

我不知道大家感受如何,我是以为比我一开始的代码,好看多了,并且逼格高了一些?

我将这个抽了出来, 写在了 github 上, 若是感兴趣的小伙伴能够去看一下哈 ~

传送门 : AdapterAPI

主要功能

  • 经过 axios 进行封装的统一请求 ✅
  • url进行判断处理,✅
  • 进行了 http code 的状态处理 ✅
  • 进行了后端返回的数据状态码处理 ✅

注意

💥 代码不必定能直接使用,目的不是让你直接搬过来用的

🔶 虽然可能我写的都不比你的好 ~ 可是但愿能够给你一些参考~

最后多说两句话

掘金太多了人才了,我这边只是记录一下一些学习过程当中的平常踩坑,或者代码的演变过程,固然,我相信有人天生就有计算机的天赋,我自认为我没有,可是我喜欢敲代码,我相信勤能补拙,不要每天作一些反复的 copy 工做就行了,望安好 ~

文章首发地址 : 📢 阿宽的博客

相关文章
相关标签/搜索