feat: show login error message; add request timeout & network guard; silence NavigationDuplicated
CI/CD Deploy (Web) / 构建前端镜像并部署 (push) Successful in 29s
CI/CD Deploy (Web) / 构建前端镜像并部署 (push) Successful in 29s
This commit is contained in:
+17
-14
@@ -8,6 +8,8 @@ import { TOKEN_KEY, EXPIRETIME_KEY } from '@/libs/util'
|
|||||||
|
|
||||||
// import { Spin } from 'view-design'
|
// import { Spin } from 'view-design'
|
||||||
const addErrorLog = errorInfo => {
|
const addErrorLog = errorInfo => {
|
||||||
|
// 网络错误/超时时 error.response 可能为 undefined,需兜底避免二次报错
|
||||||
|
if (!errorInfo || !errorInfo.request) return
|
||||||
const { statusText, status, request: { responseURL } } = errorInfo
|
const { statusText, status, request: { responseURL } } = errorInfo
|
||||||
let info = {
|
let info = {
|
||||||
type: 'ajax',
|
type: 'ajax',
|
||||||
@@ -15,7 +17,7 @@ const addErrorLog = errorInfo => {
|
|||||||
mes: statusText,
|
mes: statusText,
|
||||||
url: responseURL
|
url: responseURL
|
||||||
}
|
}
|
||||||
if (!responseURL.includes('save_error_logger')) store.dispatch('addErrorLog', info)
|
if (responseURL && !responseURL.includes('save_error_logger')) store.dispatch('addErrorLog', info)
|
||||||
}
|
}
|
||||||
|
|
||||||
class HttpRequest {
|
class HttpRequest {
|
||||||
@@ -29,6 +31,8 @@ class HttpRequest {
|
|||||||
headers: {
|
headers: {
|
||||||
//
|
//
|
||||||
},
|
},
|
||||||
|
// 请求超时时间(毫秒),避免后端不可用时页面一直“卡住”无反馈
|
||||||
|
timeout: 30000,
|
||||||
/** transformRequest 允许在向服务器发送前,修改请求数据,只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream**/
|
/** transformRequest 允许在向服务器发送前,修改请求数据,只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream**/
|
||||||
transformRequest: [function (data) {
|
transformRequest: [function (data) {
|
||||||
// 对data进行任意转化处理
|
// 对data进行任意转化处理
|
||||||
@@ -57,18 +61,12 @@ class HttpRequest {
|
|||||||
}
|
}
|
||||||
this.queue[url] = true
|
this.queue[url] = true
|
||||||
|
|
||||||
// 根据项目需求添加请求拦截
|
// 判断请求不是登录/登出接口的时候,检查 token 是否过期(根据业务逻辑做对应的处理)
|
||||||
//判断请求不是登陆接口的时候,字段是不是过期了,(根据业务逻辑做对应的处理)
|
if ((url.indexOf('login') < 0) && (config.url.indexOf('logout') < 0)) {
|
||||||
//console.log("进入请求拦截器...")
|
|
||||||
//console.log(url)
|
|
||||||
|
|
||||||
if ((url.indexOf('login') < 0) && (config.url.indexOf('logout') )) {
|
|
||||||
let curTime = new Date().getTime()
|
let curTime = new Date().getTime()
|
||||||
let expireTime = store.state.user.expireTime // 获取token过期时间
|
let expireTime = store.state.user.expireTime // 获取token过期时间
|
||||||
//console.log(expireTime)
|
|
||||||
if (expireTime) {
|
if (expireTime) {
|
||||||
let lessTime = eval(expireTime - curTime); // 后台返回的过期时间与现在的进行计算
|
let lessTime = eval(expireTime - curTime); // 后台返回的过期时间与现在的进行计算
|
||||||
//console.log(lessTime)
|
|
||||||
if (lessTime <= 0) {
|
if (lessTime <= 0) {
|
||||||
Notice.warning({
|
Notice.warning({
|
||||||
title: '登录过期',
|
title: '登录过期',
|
||||||
@@ -76,7 +74,6 @@ class HttpRequest {
|
|||||||
})
|
})
|
||||||
Cookies.remove(TOKEN_KEY);
|
Cookies.remove(TOKEN_KEY);
|
||||||
Cookies.remove(EXPIRETIME_KEY);
|
Cookies.remove(EXPIRETIME_KEY);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,11 +84,17 @@ class HttpRequest {
|
|||||||
})
|
})
|
||||||
// 响应拦截
|
// 响应拦截
|
||||||
instance.interceptors.response.use(res => {
|
instance.interceptors.response.use(res => {
|
||||||
// 根据项目需求添加响应拦截
|
|
||||||
//console.log("进入响应拦截器...")
|
|
||||||
//console.log(res.data.code )
|
|
||||||
|
|
||||||
let code = res.data.code
|
let code = res.data.code
|
||||||
|
|
||||||
|
// 登录接口:业务失败(HTTP 200 + code!=200,如用户名或密码错误)
|
||||||
|
// 直接 reject,由登录页展示后端返回的 message,不触发全局登出逻辑
|
||||||
|
if (url.indexOf('/login') > -1) {
|
||||||
|
this.destroy(url)
|
||||||
|
const { data, status } = res
|
||||||
|
if (code && code !== 200) return Promise.reject(res.data)
|
||||||
|
return { data, status }
|
||||||
|
}
|
||||||
|
|
||||||
if (code === 415){
|
if (code === 415){
|
||||||
// 1、用户名或密码错误
|
// 1、用户名或密码错误
|
||||||
Notice.warning({
|
Notice.warning({
|
||||||
|
|||||||
@@ -11,6 +11,15 @@ import { getPermissionList } from '@/api/sys/sys-permission'
|
|||||||
const {homeName} = config
|
const {homeName} = config
|
||||||
|
|
||||||
Vue.use(Router)
|
Vue.use(Router)
|
||||||
|
|
||||||
|
// vue-router 对“重复导航到当前路由”会抛出 NavigationDuplicated(Promise rejection),
|
||||||
|
// 在关闭标签页、快速点击菜单等场景会向控制台报错,这里统一静默掉这种冗余导航
|
||||||
|
const originalPush = Router.prototype.push
|
||||||
|
Router.prototype.push = function push (location, onResolve, onReject) {
|
||||||
|
if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject)
|
||||||
|
return originalPush.call(this, location).catch(err => err)
|
||||||
|
}
|
||||||
|
|
||||||
const router = new Router({
|
const router = new Router({
|
||||||
routes,
|
routes,
|
||||||
mode: 'history'
|
mode: 'history'
|
||||||
|
|||||||
@@ -51,16 +51,17 @@ export default {
|
|||||||
ip
|
ip
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
let data = res.data
|
let data = res.data
|
||||||
console.log("data:", data)
|
|
||||||
if (data.code === 200) {
|
if (data.code === 200) {
|
||||||
let token = data.token
|
let token = data.token
|
||||||
console.log("token:", token)
|
|
||||||
commit('setToken', token)
|
commit('setToken', token)
|
||||||
let curDate = new Date()
|
let curDate = new Date()
|
||||||
let expireTime = curDate.getTime() +24*60*60*1000 // 假设过期时间为后一天24*60*60*1000
|
let expireTime = curDate.getTime() +24*60*60*1000 // 假设过期时间为后一天24*60*60*1000
|
||||||
commit('setExpireTime',expireTime)
|
commit('setExpireTime',expireTime)
|
||||||
}
|
|
||||||
resolve(data)
|
resolve(data)
|
||||||
|
} else {
|
||||||
|
// 登录失败(如用户名或密码错误):把错误抛出给页面提示
|
||||||
|
reject(new Error(data.message || '登录失败,请稍后重试'))
|
||||||
|
}
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
reject(err)
|
reject(err)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -47,7 +47,8 @@
|
|||||||
'getUserInfo'
|
'getUserInfo'
|
||||||
]),
|
]),
|
||||||
handleSubmit({username, password}) {
|
handleSubmit({username, password}) {
|
||||||
var ip = returnCitySN["cip"]
|
// returnCitySN 由 index.html 引用的第三方脚本定义,可能加载失败,需兜底
|
||||||
|
var ip = (typeof returnCitySN !== 'undefined' && returnCitySN) ? returnCitySN["cip"] : ''
|
||||||
this.$refs.loginForm.loading = true
|
this.$refs.loginForm.loading = true
|
||||||
this.handleLogin({username, password, ip}).then(res => {
|
this.handleLogin({username, password, ip}).then(res => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -56,7 +57,14 @@
|
|||||||
name: this.$config.homeName
|
name: this.$config.homeName
|
||||||
})
|
})
|
||||||
}, 400)
|
}, 400)
|
||||||
|
}).catch(err => {
|
||||||
|
// 登录失败 / 后端不可用 / 请求超时统一在此提示,并复位按钮 loading
|
||||||
|
this.$refs.loginForm.loading = false
|
||||||
|
let msg = (err && err.message) ? err.message : ''
|
||||||
|
if (!msg || msg.indexOf('Network Error') > -1 || msg.indexOf('timeout') > -1 || msg.indexOf('ECONNABORTED') > -1) {
|
||||||
|
msg = '网络异常或服务不可用,请稍后重试'
|
||||||
|
}
|
||||||
|
this.$Message.error(msg)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user