axios的get请求需要对值进行RFC 3986编码的解决方案

29 阅读1分钟

背景

操作

创建axios实例时增加一个配置属性
  paramsSerializer(params) {
    return qs.stringify(params, { format: 'RFC3986', encodeValuesOnly: true });
  },
  • 整体方案
---------- commonjs -----------------------
import RandExp from 'randexp'
import CryptoJS from 'crypto-js/crypto-js'

//客户端唯一id
export const uniqueId = () => RandExp.randexp(/[\da-z]{8}-[\da-z]{4}-[\da-z]{4}-[\da-z]{4}-[\da-z]{12}/)

export function sha256Hex(data) {
  return CryptoJS.SHA256(data);
}

export function hmacsha256(val, key) {
  return CryptoJS.HmacSHA256(val, key).toString();
}

export function getEopDate() {
  const now = new Date(new Date().getTime() + 480 * 60000);
  const ret = now.toISOString();//东八区
  return ret.substring(0, ret.indexOf(".")).replaceAll("-", "").replaceAll(":", "") + "Z";
}
----------- 创建实例 ---------------
let request = axios.create({
  // baseURL: "https://ecpc-global.ctapi.ctyun.cn",
  timeout: TIME_OUT,
  paramsSerializer(params) {
    return qs.stringify(params, { format: 'RFC3986', encodeValuesOnly: true });
  }
})

request.interceptors.request.use((config)=>{
  let id = uniqueId()
  let date = getEopDate()
  const KEY_REQ_ID = "ctyun-eop-request-id";
  const KEY_EOP_DATE = "eop-date";
  const KEY_EOP_AUTH = "Eop-Authorization";
  const ak = '0deagf44fsdfasdqed44df4dfasdfsdddd'
  const sk = 'gfhavcfsdhl41f52sdfsdf1a53f4sdffff'
  // ****signature****************
  const sigHeader = `${KEY_REQ_ID}:${id}\n${KEY_EOP_DATE}:${date}\n`

  let params = ''
  if (config.params) {
    // 尽管paramsSerializer会使query 里的字符转义,这儿的params的值还是原始值
    params = qs.stringify(config.params, { format: 'RFC3986', encodeValuesOnly: true });
    params = params.split("&").sort().join("&")
  }

  const body = JSON.stringify(config.data) ?? ''
  // sha256Hex('') 是有值的

  const sigture = `${sigHeader}\n${params}\n${sha256Hex(body)}`
  // ***********kdate**********
  const ktime = hmacsha256(date, sk)
  const kAk = hmacsha256(ak, CryptoJS.enc.Hex.parse(ktime))
  const kdate = hmacsha256(date.split('T')[0], CryptoJS.enc.Hex.parse(kAk))
  // *********signature*****************
  const Signature = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Hex.parse(hmacsha256(sigture, CryptoJS.enc.Hex.parse(kdate))));

  config.headers[KEY_REQ_ID] = id
  config.headers[KEY_EOP_DATE] = date
  config.headers[KEY_EOP_AUTH] = `${ak} Headers=ctyun-eop-request-id;eop-date Signature=${Signature}`
  return config
})

区别(网上找的)

  • 误区:使用axios时若未对参数进行处理,则它的转义并不是encodeURIComponent 18071078-8a2fd4a1ad25efa0.webp

x-www-form-urlencoded编码规则如下:

  1. 将key和value用=连接起来。
  2. 每个键值对之间用&符号连接。
  3. 对每个键值对中的进行编码,调用encodeURIComponent()函数实现。此函数编码除字母、数字、-、_、.、!、~、*、'、(、)外的字符,同时将空格编码为%20。
  4. ajax的post请求 传 qs.stringify(param),会自动设置 content-type

摘自:www.python100.com/html/32FHMO…