在获取接口时,总是提示签名重复,卡了两天,最后还是靠大神帮忙解决这个问题。
我一开始就是直接给请求头部添加签名,但没注意到这样必不会每次生成不一样的echostr,下面是错误的代码:
let access_key = 'xxx'; // 服务端生成的 access_key
let secret_key = 'xxx'; // 服务端生成的 secret_key
let headers = {
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'api-access-key': access_key
}
function encrypting(secret_key, echostr, timestamp) {
return md5(secret_key + echostr + timestamp); // md5 库自行引入
}
let timestamp = Date.now() / 1000;
let echostr = randomWord(false, 8);
axios.defaults.headers['api-timestamp'] = timestamp
axios.defaults.headers['api-echostr'] = echostr
axios.defaults.headers['api-signature'] = encrypting(secret_key, echostr, timestamp)
axios.defaults.headers['Authorization'] = `Bearer ${token}`
后来大神一眼就看出问题,下图是大神修改后的代码(封装axios是从网上找的,自己改了一些,还有一些其他问题的存在,建议如果需要使用,根据需要修改):
'use strict'
import qs from 'qs'
import md5 from 'js-md5'
import axios from "axios"
import {
randomWord
} from './common'
window.axios = axios;
// 超时时间
window.axios.defaults.timeout = 9000;
// http request 拦截器
window.axios.interceptors.request.use(config => {
return config;
}, err => {
// TODO: 使用 UI 框架弹出错误
console.error(err);
return Promise.resolve(err);
})
// http response 拦截器 与后台提前定义正确code 错误的提示
window.axios.interceptors.response.use(
response => {
if (response.data.code === 0) {
return response
} else if (response.config.responseType === 'blob') {
return response
} else {
// TODO: 使用 UI 框架弹出错误
console.error(response.data.msg)
return Promise.reject(response)//Promise.reject(response)
}
},
error => {
if (error.response) {
switch (error.response.status) {
case 400:
error.message = '请求错误(400)';
break;
case 401:
error.message = '未授权,请重新登录(401)';
break;
case 403:
error.message = '拒绝访问(403)';
break;
case 404:
error.message = '请求出错(404)';
break;
case 408:
error.message = '请求超时(408)';
break;
case 500:
error.message = '服务器错误(500)';
break;
case 501:
error.message = '服务未实现(501)';
break;
case 502:
error.message = '网络错误(502)';
break;
case 503:
error.message = '服务不可用(503)';
break;
case 504:
error.message = '网络超时(504)';
break;
case 505:
error.message = 'HTTP版本不受支持(505)';
break;
}
console.log(error.response.status)
} else {
console.log(error)
}
return Promise.reject(error.response ? error.response.data : error)
}
)
function checkStatus(response) {
// loading
// 如果http状态码正常,则直接返回数据
if (response && (response.status === 200 || response.status === 304 || response.status === 400)) {
return response
// 如果不需要除了data之外的数据,可以直接 return response.data
}
if (response && response.status === 401) {
alert("登陆已过期,请重新登陆!")
}
// 异常状态下,把错误信息返回去
return {
status: 404,
msg: '网络异常'
}
}
function checkCode(res) {
// 如果code异常(这里已经包括网络错误,服务器错误,后端抛出的错误),可以弹出一个错误提示,告诉用户
// debugger
if (res.status === 404) {
console.log(res.msg)
}
if (res.data && (!res.data.success)) {
console.log("code异常",res.data.code)
}
return res
}
let access_key = '服务端生成的 access_key'; // 服务端生成的 access_key
let secret_key = '服务端生成的 secret_key'; // 服务端生成的 secret_key
let headers = {
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'api-access-key': access_key
}
function encrypting(secret_key, echostr, timestamp) {
return md5(secret_key + echostr + timestamp); // md5 库自行引入
}
// TODO: debug
export function getDefaultHeaders() {
let token = ''
try {
console.log("call mobile.getUserToken trying...")
token = mobile.getUserToken();
console.log("call mobile.getUserToken done ...", token)
} catch (e) {}
if (!token) {
try {
token = JSON.parse(sessionStorage.getItem("userInfo")).token;
} catch (e) {}
}
if (!token) {
try {
token = JSON.parse(window.userInfoRaw).token;
} catch(e) {}
}
let timestamp = Date.now() / 1000;
let echostr = randomWord(false, 8);
return Object.assign(headers, {
'api-timestamp': timestamp,
'api-echostr': echostr,
'api-signature': encrypting(secret_key, echostr, timestamp),
'Authorization': `Bearer ${token}`
})
}
export default {
get: (url, params) => {
return window.axios({
method: 'get',
url,
params, // get 请求时带的参数
headers: getDefaultHeaders()
}).then(
(response) => {
return checkStatus(response)
}
).catch(
(res) => {
return checkCode(res)
}
)
},
post: (url, data, config = {}) => {
return window.axios({
method: 'post',
url,
data: qs.stringify(data),
headers: Object.assign(getDefaultHeaders(), config.headers)
}).then(
(response) => {
return checkStatus(response)
}
).catch(
(res) => {
return checkCode(res)
}
)
},
upload: (url, data) => {
return window.axios({
method: 'post',
url,
data: data,
headers: getDefaultHeaders()
}).then(
(response) => {
return checkStatus(response)
}
).catch(
(res) => {
return checkCode(res)
}
)
},
put: (url, params) => {
return window.axios({
method: 'put',
url,
data: qs.stringify(params),
headers: getDefaultHeaders()
}).then(
(response) => {
return checkStatus(response)
}
).catch(
(res) => {
return checkCode(res)
}
)
},
delete: (url, params) => {
return window.axios({
method: 'delete',
url,
data: qs.stringify(params),
headers: getDefaultHeaders()
}).then(
(response) => {
return checkStatus(response)
}
).catch(
(res) => {
return checkCode(res)
}
)
}
}
使用封装方法
//API.js
import axios from 'axios'
import http from './http'
const host = '/xxx';
//获取用户信息
export function UserInfo(){
let userInfo = window.sessionStorage.getItem('userInfo');
try {
userInfo = JSON.parse(userInfo);
} catch (e) {
userInfo = null;
}
return userInfo;
}
//获取广告列表
export function GetData(options) { //在这里用options,方便按需加参数,当然也可以固定写死参数,看自己的需求
const url = host + "/xxx";
return http.get(url, options)
}
//index.vue