axios请求头设置常见Content-Type和对应参数的处理

海哥  金牌会员 | 2022-6-23 22:20:07 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 896|帖子 896|积分 2688

一,Content-Type

首先要明确的一点是,我们在项目中调用接口,通常是以对象的数据格式传给自己封装的http请求函数的。
1,application/json

现在的前后端分离项目基本上都是使用的这个进行数据传递。
axios默认Content-type是采用application/json;charset=UTF-8,无需设置直接把对象传进去即可
当然,也可以在请求拦截器中转化成json后再发请求(但是不能用qs.stringify)
  1. config.data = JSON.stringify(config.data)
复制代码
2,application/x-www-form-urlencoded

  1. "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
复制代码
用于表单的提交。值得注意的是,ajax 中(不是axios哈), contentType都是默认的值:application/x-www-form-urlencoded。
特点是提交的参数按照 key1=val1&key2=val2 的方式进行编码,key 和 val 会进行了 URL 转码。
而要实现这种参数的序列化,最简单的方法是引入qs库。做如下的配置。
  1. import Qs from "qs"
  2. // 创建axios实例
  3.     const service = axios.create({
  4.       baseURL: process.env.VUE_APP_baseUrl,
  5.       timeout: 5000,
  6.      ...//其他配置
  7.      //transformRequest用来对请求参数提前进行处理
  8.       transformRequest: [data => Qs.stringify(data, { indices: true })] //Qs.stringify将参数序列化成key=value&key=value的形式,indices: true是配置参数有传数组的时候,以下标的形式
  9.     })
复制代码
比如说,当我们传递的参数是:
  1. {
  2.         title:'标题',
  3.         list:[1,2,3]
  4. }
复制代码
则会被转化成:title=标题&list[0]=1&list[1]=2&list[2]=3的形式。
  1. Qs.stringify(data, { indices: true }//这个如果用false的话。传数组就是title=标题&list=1&list=2&list=3的形式了,也就是不带索引。
复制代码
结合上文,在content-tyoe=application/x-www-form-urlencoded时,我们在页面中传的是对象,然后通过Qs.stringify把参数转换成key=value的形式了,这才可以发出正确的http请求。
另外,Qs.stringify配置的场合也可以有多个。如下图在axios中进行配置。

3,multipart/form-data

这也是一个常见的 POST 数据提交的方式。我们使用表单上传文件时,就要让 form 的 enctype 等于这个值。这种方式一般用来上传文件,各大服务端语言对它也有着良好的支持。这个和application/x-www-form-urlencoded的区别在于一个适合传字段键值,一个适合传文件。
二,qs.sringify和JSON.stringify的区别

假设我要提交的数据是:
  1. var a = {name:'hehe',age:10};
复制代码
qs.stringify序列化结果如下
  1. name=hehe&age=10
复制代码
而JSON.stringify序列化结果如下:
  1. "{"a":"hehe","age":10}"
复制代码
三,项目中的实际应用

这个项目呢,大多数post请求,后端的接口设计的是application/x-www-form-urlencoded类型的content-type。唯独有一个接口设计的是application/json。但是我最开始content-type的设置是在全局的axios中进行配置的,全都配置成application/x-www-form-urlencoded。于是需要分类下,使用application/x-www-form-urlencoded的时候,需要key-value序列化处理,而另一种application/json的则不需要。
  1. import axios from "axios"
  2. import { Message as showMessage } from "element-ui"
  3. import errorCode from "./errorCode"
  4. // import store from "@/store"
  5. import Qs from "qs"
  6. // axios.defaults.headers["Content-Type"] = "application/json" //底下创建axios实例时配置了,这个不用重复配置,再说,这也是axios的默认配置
  7. export default function request(options) {
  8.   return new Promise((resolve, reject) => {
  9.     // 创建axios实例
  10.     const service = axios.create({
  11.       // 表示请求URL公共部分,它会读取这里的值,然后拼接上页面使用的url
  12.       baseURL: process.env.VUE_APP_baseUrl,
  13.       timeout: 5000,
  14.       withCredentials: false, // 跨域请求时是否需要cookie等凭证
  15.       responseType: "json",
  16.       params: {},
  17.       maxContentLength: 2000,
  18.       validateStatus: status => status >= 200 && status < 300, //默认值
  19.       maxRedirects: 5, //最大允许重定向次数
  20.       headers: {
  21.         //公共请求头配置,本项目请求头大多数接口是这个,所以这里可以配置一下,对于特殊接口单独配置
  22.         "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
  23.       }
  24.       // transformRequest: [data => Qs.stringify(data, { indices: true })] //将参数key=value序列化,因为本项目有的接口需要json/对象传参数,这里就不能这样直接全局配置,否则有的接口会报400(因为你把json或者是对象类型的数据,在这里key=value序列化了)
  25.     })
  26.     // request拦截器
  27.     service.interceptors.request.use(
  28.       config => {
  29.         switch (config.method) {
  30.           case "get":
  31.             if (!config.params) {
  32.               config.params = {}
  33.             }
  34.             break
  35.           case "post":
  36.             if (!config.data) {
  37.               config.data = {}
  38.             }
  39.             if (config.type === "keyValue") {
  40.               config.data = Qs.stringify(config.data) //配套application/x-www-form-urlencoded使用
  41.             } else {
  42.               config.headers["Content-Type"] = "application/json" //配套application/json使用
  43.             }
  44.             break
  45.           default:
  46.         }
  47.         console.log(`【request】url:${config.url},data:${config.data} `)
  48.         return config
  49.       },
  50.       error => {
  51.         console.log(error)
  52.         Promise.reject(error)
  53.       }
  54.     )
  55.     // 响应拦截器
  56.     service.interceptors.response.use(
  57.       res => {
  58.         // 未设置状态码则默认成功状态
  59.         const code = parseInt(res.data.code) || 0
  60.         // 获取错误信息
  61.         const msg = res.data.msg || errorCode[code] || errorCode["default"]
  62.         if (code != 0) {
  63.           showMessage({
  64.             message: msg,
  65.             type: "error"
  66.           })
  67.           reject(new Error(msg))
  68.           return
  69.         } else {
  70.           resolve(res.data) //获取到成功的响应了,就把结果resolve出去
  71.         }
  72.       },
  73.       error => {
  74.         console.log("err" + error)
  75.         let { message } = error
  76.         if (message == "Network Error") {
  77.           message = "网络异常,请检查网络"
  78.         } else if (message.includes("timeout")) {
  79.           message = "系统接口请求超时,请检查网络"
  80.         } else if (message.includes("Request failed with status code")) {
  81.           message = "系统接口" + message.substr(message.length - 3) + "异常"
  82.         }
  83.         showMessage({
  84.           message: message,
  85.           type: "error",
  86.           duration: 5 * 1000
  87.         })
  88.         return reject(error)
  89.       }
  90.     )
  91.     service(options)
  92.   })
  93. }
复制代码
然后请求的封装:
  1. import request from "./request.js"
  2. import { Loading } from "element-ui"
  3. let http = {
  4.   /** post 请求
  5.    * @param  {接口地址} url
  6.    * @param  {请求参数} params
  7.    * @param  {请求的参数处理类型}
  8.    * keyValue:默认的application/x-www-form-urlencoded,使用qs.stringify序列化。
  9.    * json:使用application/json,不用处理参数
  10.    */
  11.   post: function (url, params, type = "keyValue") {
  12.     let loadingInstance = Loading.service({
  13.       lock: true,
  14.       text: "请稍候",
  15.       spinner: "el-icon-loading",
  16.       background: "rgba(0, 0, 0, 0.7)",
  17.       fullscreen: false,
  18.       customClass: "loadingClass"
  19.     })
  20.     return new Promise((resolve, reject) => {
  21.       request({
  22.         url,
  23.         method: "post",
  24.         data: params,
  25.         type
  26.       })
  27.         .then(response => {
  28.           loadingInstance.close()
  29.           resolve(response)
  30.         })
  31.         .catch(error => {
  32.           loadingInstance.close()
  33.           reject(error)
  34.         })
  35.     })
  36.   }
  37. }
  38. export default http
复制代码
页面中使用application/json的接口的调用:
  1. async newDog() {
  2.       const that = this
  3.       let params = {
  4.         ...this.petForm
  5.       }
  6.       try {
  7.         let res = await that.$http.post("/dog/newDog", params, "json")
  8.         console.log("--接口请求成功--", res)
  9.         that.$message({
  10.           message: "接口请求成功",
  11.           type: "success"
  12.         })
  13.       } catch (err) {
  14.         console.log("报错了:", err)
  15.       }
  16. },
复制代码
大致的设计思路:


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

海哥

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表