92 lines
2.3 KiB
JavaScript
92 lines
2.3 KiB
JavaScript
import axios from 'axios'
|
||||
|
|
import { ElMessage } from 'element-plus'
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 统一请求封装:
|
|||
|
|
* - 请求头自动携带 Bearer token
|
|||
|
|
* - 响应头 X-Renewed-Token 自动保存(滑动续签)
|
|||
|
|
* - 401 清除登录态并跳转登录页
|
|||
|
|
* - 业务 code!==0 弹错并 reject;data 缺省时返回原响应体
|
|||
|
|
*/
|
|||
|
|
const TOKEN_KEY = 'ws_token'
|
|||
|
|
const USER_KEY = 'ws_user'
|
|||
|
|
|
|||
|
|
export function getToken() {
|
|||
|
|
return localStorage.getItem(TOKEN_KEY) || ''
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export function setToken(token) {
|
|||
|
|
localStorage.setItem(TOKEN_KEY, token)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export function getUser() {
|
|||
|
|
try {
|
|||
|
|
return JSON.parse(localStorage.getItem(USER_KEY)) || {}
|
|||
|
|
} catch {
|
|||
|
|
return {}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export function setAuth(token, user) {
|
|||
|
|
localStorage.setItem(TOKEN_KEY, token)
|
|||
|
|
localStorage.setItem(USER_KEY, JSON.stringify(user || {}))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export function clearAuth() {
|
|||
|
|
localStorage.removeItem(TOKEN_KEY)
|
|||
|
|
localStorage.removeItem(USER_KEY)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const service = axios.create({
|
|||
|
|
baseURL: '',
|
|||
|
|
timeout: 30000
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
service.interceptors.request.use((config) => {
|
|||
|
|
const token = getToken()
|
|||
|
|
if (token) config.headers.Authorization = 'Bearer ' + token
|
|||
|
|
return config
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
service.interceptors.response.use(
|
|||
|
|
(response) => {
|
|||
|
|
// 滑动续签:后端剩余有效期不足一半时下发新 token
|
|||
|
|
const renewed = response.headers?.['x-renewed-token']
|
|||
|
|
if (renewed) setToken(renewed)
|
|||
|
|
|
|||
|
|
const d = response.data
|
|||
|
|
if (d && typeof d === 'object' && 'code' in d) {
|
|||
|
|
if (d.code !== 0) {
|
|||
|
|
const err = new Error(d.message || '请求失败')
|
|||
|
|
showErrThrottled(err.message)
|
|||
|
|
return Promise.reject(err)
|
|||
|
|
}
|
|||
|
|
return d.data !== undefined ? d.data : d
|
|||
|
|
}
|
|||
|
|
return d
|
|||
|
|
},
|
|||
|
|
(error) => {
|
|||
|
|
if (error.response && error.response.status === 401) {
|
|||
|
|
clearAuth()
|
|||
|
|
window.location.hash = '#/login'
|
|||
|
|
error.message = '登录已失效,请重新登录'
|
|||
|
|
} else {
|
|||
|
|
error.message =
|
|||
|
|
error.response?.data?.message ||
|
|||
|
|
(error.code === 'ECONNABORTED' ? '请求超时' : '网络异常:' + (error.message || '未知错误'))
|
|||
|
|
}
|
|||
|
|
showErrThrottled(error.message)
|
|||
|
|
return Promise.reject(error)
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
let lastErrAt = 0
|
|||
|
|
function showErrThrottled(msg) {
|
|||
|
|
// 简单节流,避免轮询接口失败刷屏(3 秒内只提示一次)
|
|||
|
|
const now = Date.now()
|
|||
|
|
if (now - lastErrAt < 3000) return
|
|||
|
|
lastErrAt = now
|
|||
|
|
ElMessage.error(msg)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export default service
|