# Axios 的请求封装后的使用

# 引子

​ 作为一名不标准的后端 Java 开发工程师,对于前端 HTML5,CSS3,JS 熟悉,对于 Nodojs 却不胜了解,也算接触写过不少 Vue 系列的后端管理页面。对其中的 Axios 的请求封装后的简易接口调用方法感觉很有意思。特地记录

# Axios 实现例子

# Axios 封装请求

Axios 的封装主要围绕三点,第一步创建 Axios 实例,第二步设置实例的请求拦截器,第三步设置实例的相应拦截器

import axios from 'axios'
import { Message } from 'element-ui'
/**
 * @description 创建请求实例
 */
function createService () {
  // 创建一个 axios 实例
  const service = axios.create()
  // 请求拦截
  service.interceptors.request.use(
    config => config,//config 是后期传入的
    error => {
      // 开始请求时出现错误,指还没到对面服务器就发送失败
      console.log(error)
      return Promise.reject(error)
    }
  )
  // 响应拦截
  service.interceptors.response.use(
    response => {
      //dataAxios 是 axios 返回数据中的 data
      const dataAxios = response.data
      // 这个状态码是和后端约定的
      const { code } = dataAxios
      // 根据 code 进行判断
      if (code === undefined) {
        // 如果没有 code 代表这不是项目后端开发的接口
        return dataAxios
      } else {
        // 有 code 代表这是一个后端接口 可以进行进一步的判断
        switch (code) {
          case 'SUCCESS':
           	localStorage.setItem('token', response.headers.retoken)
            return dataAxios.data
          case '400':
            Message({
              message: dataAxios.message,
              type: 'error',
              duration: 2 * 1000
            })
            break
          case 'xxx':
            // [示例] 其它和后台约定的 code
            break
          default:
            // 不是正确的 code
            break
        }
      }
    },
    error => {
      return Promise.reject(error)
    }
  )
  return service
}
/**
 * @description 创建请求方法
 * @param {Object} service axios 实例
 */
function createRequestFunction (service) {
  return function (config) {
    const token = localStorage.getItem('token')
    const configDefault = {
      headers: {
        token: token,
      },
      timeout: 5000,
      baseURL: 'https://localhost:8080/',
      data: {}
    }
    /**
     * Object.assign 函数可以理解为,第一个对象 configDefault 融合第二个对象 config 的所有字段
     * 第二个对象参数一般是
     * {
     *   url: '/app-info/list',
     *   method: 'get',
     *   params: data
     * }
     */
    return service(Object.assign(configDefault, config))
  }
}
// 设置请求
export const service = createService()
export const request = createRequestFunction(service)

# 使用封装后的请求

​ 通过上面的例子,我们可以很明显的看出我们的入参和 Ajax 参数神似。而在日常的使用中,大部分人常常忽视 headers 请求头的 Content-Type 属性的作用只会使用如下请求来解决后端 GET 请求键值对传值,POST 请求 JSON 字符串传值。因为这也是后端接口提供入参的常态。

#GET
return request({
  url: '/app-info/list',
  method: 'get',
  params: data
})
#POST
return request({
  url: '/app-info/delete',
  method: 'post',
  data: data
})

​ 但当我前后端开发时,也会写这种正规的接口,但总有那么几次参数是两个,请求是 POST,但又不想改请求类型,也不想把两个键值对参数换 JSON 字符串对象,纠结过几次但都用前面两种方式解决,但对于这件事情耿耿于怀,因为自身对前端的这种请求也属于会用而不能熟练用 Σ(っ °Д °;) っ,也看过很多人写的例子,感觉都不是我想要的。

# 如何实现 POST 请求键值对传值

# JAVA 后端接口例子

@PostMapping("/postTest")
@ResponseBody
public Object get(String password,String name){
    HashMap<String, String> stringStringHashMap = new HashMap<>();
    stringStringHashMap.put("name",name);
    stringStringHashMap.put("password",password);
    return stringStringHashMap;
}

# Axios 官方介绍

	从官方介绍上很直接的可以看到 Axios 会帮我们 转换请求数据和响应数据 以及 自动转换 JSON 数据 

image-20210108134321845

​ 随后就在上面直接找到了官方解决方案,有好几种

image-20210108135419674

​ 随后我在源码处也找到了 Axios 关于参数的转换,文件路径:axios/dist/axios.jsimage-20210108140227108

​ 然后我再收集了 Axios 的参数及含义

url —— 用来向服务器发送请求的url
method —— 请求方法,默认是GET方法
baseURL —— 基础URL路径,假如url不是绝对路径,如https://some-domain.com/api/v1/login?name=jack,那么向服务器发送请求的URL将会是baseURL + url。
transformRequest —— transformRequest方法允许在请求发送到服务器之前修改该请求,此方法只适用于PUT、POST和PATCH方法中。而且,此方法最后必须返回一个string、ArrayBuffer或者Stream。
transformResponse —— transformResponse方法允许在数据传递到then/catch之前修改response数据。此方法最后也要返回数据。
headers —— 发送自定义Headers头文件,头文件中包含了http请求的各种信息。
params —— params是发送请求的查询参数对象,对象中的数据会被拼接成url?param1=value1&param2=value2。
paramsSerializer —— params参数序列化器。
data —— data是在发送POST、PUT或者PATCH请求的数据对象。
timeout —— 请求超时设置,单位为毫秒
withCredentials —— 表明是否有跨域请求需要用到证书
adapter —— adapter允许用户处理更易于测试的请求。返回一个Promise和一个有效的response
auth —— auth表明提供凭证用于完成http的身份验证。这将会在headers中设置一个Authorization授权信息。自定义Authorization授权要设置在headers中。
responseType —— 表示服务器将返回响应的数据类型,有arraybuffer、blob、document、json、text、stream这6个类型,默认是json类似数据。
xsrfCookieName —— 用作 xsrf token 值的 cookie 名称
xsrfHeaderName —— 带有 xsrf token 值 http head 名称
onUploadProgress —— 允许在上传过程中的做一些操作
onDownloadProgress —— 允许在下载过程中的做一些操作
maxContentLength —— 定义了接收到的response响应数据的最大长度。
validateStatus —— validateStatus定义了根据HTTP响应状态码决定是否接收或拒绝获取到的promise。如果 validateStatus 返回 true (或设置为 null 或 undefined ),promise将被接收;否则,promise将被拒绝。
maxRedirects —— maxRedirects定义了在node.js中redirect的最大值,如果设置为0,则没有redirect。
httpAgent —— 定义在使用http请求时的代理
httpsAgent —— 定义在使用https请求时的代理
proxy —— proxy定义代理服务器的主机名和端口,auth
cancelToken —— cancelToken定义一个 cancel token 用于取消请求

# 关键词介绍

​ 从前面的信息来看我们已经找到了方向也明白了如何实现,但对于更清晰的使用还是很模糊的,所以我们需要再明白一些信息

# URLSearchParams 对象

​ URLSearchParams 对象是一个可以将 JSON 对象转换为 name=昔日长廊&password=昔日织 这种字符串对象。而后端的入参也是从这种字符串内取参。而这种格式出现在 form 表单请求时,headers 请求头参数 Content-Type 值为 application/x-www-form-urlencoded 时。也常用于 GET 请求地址后面的拼接带参。如下 POST 请求也能这样传参。

image-20210108141659052image-20210108142956001

image-20210108143020145

可以看到后台接受到了参数,但注意 headers 请求头参数 Content-Type 值为 application/json;charset=utf-8,这说明参数已经不是一个 URLSearchParams 对象,URL 路径也非常像 GET 请求。而原因的产生是因为 Axios 的参数内的 params

# params 与 data 参数

​ data 参数没有什么问题,不会做什么数据处理,但 params 参数会做数据处理,它会将 JSON 对象转为 name=昔日长廊&password=昔日织 这种字符串,它和 URLSearchParams 对象的区别你可以理解为 JS 的数组 [] 和 Array 对象的区别,他们本质上数据结构是一样,只是实现的方式不一样,自然这些方式内方法也不一样,在 JAVA 语言中就是继承,实现的效果。所以使用 params 时在对 URLSearchParams 对象处理时就转个字符串就行了。

​ 证明:因为直接打印 URLSearchParams 对象的字符串模式,并使用 data 传参并成功

image-20210108145649018

image-20210108145836561

image-20210108145912503

# 总结

​ 总算解决了心里的一个疑惑。也对 Axios 又有了一个使用方式的经验

# 2021.09.17 补充

经朋友提示后端接口为 List 对象时不转 JSON 格式无法入参,会报找不到接口 java.util.List 的主要或默认构造函数方法。解决办法要么使用数组 [],要么前面加上 @RequestParam 才行。