Commit e34be04d authored by 水玉婷's avatar 水玉婷
Browse files

feat:401问题

parent 5b851fbb
......@@ -2,15 +2,25 @@ import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { setRouter } from './utils/router-manager'
import createFetchInterceptor from './utils/fetch-interceptor'
import { initGlobalErrorHandler, handle401Error, is401Error } from './utils/error-handler'
const app = createApp(App)
app.use(router)
// 设置全局路由实例
setRouter(router)
// 启用fetch拦截器 - 自动处理401错误
createFetchInterceptor()
// 全局错误处理 - 项目级别的401拦截机制
app.config.errorHandler = (err, instance, info) => {
console.error('Vue全局错误捕获:', err, info)
// 处理401错误
if (is401Error(err)) {
console.log('Vue错误处理中检测到401,执行全局处理')
handle401Error()
}
}
// 初始化全局错误处理机制
initGlobalErrorHandler()
app.mount('#app')
\ No newline at end of file
......@@ -44,18 +44,21 @@ instance.interceptors.response.use(
},
(error) => {
if (error.response) {
const { status } = error.response
const { status, data } = error.response
// 处理401未授权错误
if (status === 401) {
// 检查是否已经在跳转过程中,防止无限循环
if (isNavigatingToLogin) {
console.log('已在跳转登录页面中,避免重复跳转')
return Promise.reject(new Error('正在跳转到登录页面'))
}
// 设置跳转标志
isNavigatingToLogin = true
console.log('检测到401错误,清除用户信息并跳转登录')
// 清除本地存储的用户信息
localStorage.removeItem('wechat_user')
......@@ -65,13 +68,14 @@ instance.interceptors.response.use(
// 3秒后重置跳转标志,防止长时间锁定
setTimeout(() => {
isNavigatingToLogin = false
console.log('重置跳转标志')
}, 3000)
return Promise.reject(new Error('未授权访问,请重新登录'))
}
// 其他错误处理
console.error(`请求失败: ${status}`, error.response.data)
console.error(`请求失败: ${status}`, data)
} else if (error.request) {
console.error('网络错误,请求未发送成功', error)
} else {
......
// 全局错误处理器 - 项目级别的401拦截机制
import { getRouter } from './router-manager'
// 防止重复跳转的标志
let isHandling401 = false
/**
* 处理401错误 - 项目级别拦截
*/
export const handle401Error = (errorMessage = '未授权访问,请重新登录') => {
// 检查是否已经在处理中,防止无限循环
if (isHandling401) {
console.log('已在处理401错误,避免重复操作')
return
}
// 设置处理标志
isHandling401 = true
console.log('执行全局401错误处理')
// 清除本地存储的用户信息
localStorage.removeItem('wechat_user')
// 获取路由实例
const router = getRouter()
// 跳转到登录页
if (router) {
// 使用replace而不是push,避免浏览器历史记录问题
router.replace('/login')
} else {
// 备用方案:直接修改URL
if (window.location.hash) {
window.location.hash = '/login'
} else {
window.location.pathname = '/login'
}
}
// 3秒后重置处理标志
setTimeout(() => {
isHandling401 = false
console.log('重置401处理标志')
}, 3000)
// 抛出错误以便上层可以捕获
throw new Error(errorMessage)
}
/**
* 检查是否为401错误
*/
export const is401Error = (error) => {
if (!error) return false
// 检查axios错误
if (error.response && error.response.status === 401) {
return true
}
// 检查fetch错误
if (error.status === 401) {
return true
}
// 检查错误消息
if (error.message && (
error.message.includes('401') ||
error.message.includes('未授权') ||
error.message.includes('unauthorized')
)) {
return true
}
return false
}
/**
* 全局错误拦截器
*/
export const setupGlobalErrorInterceptor = () => {
// 拦截控制台错误
const originalConsoleError = console.error
console.error = (...args) => {
// 检查是否包含401相关错误
const errorString = args.join(' ')
if (errorString.includes('401') || errorString.includes('未授权')) {
console.log('控制台检测到401错误:', errorString)
}
originalConsoleError.apply(console, args)
}
// 拦截未捕获的Promise错误
window.addEventListener('unhandledrejection', (event) => {
const error = event.reason
if (is401Error(error)) {
console.log('未捕获的Promise错误中包含401:', error)
event.preventDefault() // 阻止默认行为
handle401Error()
}
})
// 拦截未捕获的JavaScript错误
window.addEventListener('error', (event) => {
const error = event.error
if (is401Error(error)) {
console.log('未捕获的JavaScript错误中包含401:', error)
event.preventDefault() // 阻止默认行为
handle401Error()
}
})
}
/**
* 增强的fetch拦截器
*/
export const setupFetchInterceptor = () => {
const originalFetch = window.fetch
if (originalFetch) {
window.fetch = async (...args) => {
try {
const response = await originalFetch(...args)
// 检查401状态码
if (response.status === 401) {
console.log('Fetch请求返回401,执行全局处理')
handle401Error()
}
return response
} catch (error) {
if (is401Error(error)) {
handle401Error()
}
throw error
}
}
}
}
/**
* 初始化全局错误处理
*/
export const initGlobalErrorHandler = () => {
setupGlobalErrorInterceptor()
setupFetchInterceptor()
console.log('全局错误处理机制已初始化')
}
export default {
handle401Error,
is401Error,
setupGlobalErrorInterceptor,
setupFetchInterceptor,
initGlobalErrorHandler
}
\ No newline at end of file
// fetch拦截器 - 在外层处理401错误,保持组件通用性
import { navigateToLogin } from './router-manager'
// 防止重复跳转的标志
let isNavigatingToLogin = false
// 获取用户token
const getUserToken = () => {
try {
const userData = localStorage.getItem('wechat_user')
const { extMap = {} } = JSON.parse(userData || '{}')
return extMap.sessionId || ''
} catch (error) {
console.warn('解析用户信息失败', error)
return ''
}
}
// 处理401错误
const handle401Error = () => {
// 检查是否已经在跳转过程中,防止无限循环
if (isNavigatingToLogin) {
throw new Error('正在跳转到登录页面')
}
// 设置跳转标志
isNavigatingToLogin = true
// 清除本地存储的用户信息
localStorage.removeItem('wechat_user')
// 使用全局路由管理器跳转
navigateToLogin()
// 3秒后重置跳转标志,防止长时间锁定
setTimeout(() => {
isNavigatingToLogin = false
}, 3000)
throw new Error('未授权访问,请重新登录')
}
// 创建fetch拦截器
const createFetchInterceptor = () => {
// 保存原始的fetch函数
const originalFetch = window.fetch
// 拦截fetch请求
window.fetch = async function(url, options = {}) {
// 设置默认请求头
const defaultHeaders = {
'Content-Type': 'application/json',
}
// 添加认证信息
const userToken = getUserToken()
if (userToken) {
defaultHeaders['Token'] = userToken
defaultHeaders['x-session-id'] = userToken
defaultHeaders['x-app-code'] = import.meta.env.VITE_APP_CODE || ''
}
// 合并请求头
const headers = {
...defaultHeaders,
...options.headers
}
const config = {
...options,
headers
}
try {
const response = await originalFetch.call(this, url, config)
// 检查响应状态
if (response.status === 401) {
handle401Error()
}
return response
} catch (error) {
// 如果是401错误,已经处理过,直接抛出
if (error.message.includes('未授权访问')) {
throw error
}
// 其他网络错误
console.error('网络请求失败:', error)
throw error
}
}
// 返回取消拦截的方法
return {
// 恢复原始fetch
restore: () => {
window.fetch = originalFetch
},
// 获取当前拦截器状态
isIntercepted: () => window.fetch !== originalFetch
}
}
// 导出拦截器创建函数
export default createFetchInterceptor
\ No newline at end of file
// 引入axios
import { post } from './axios.js'
// 企业微信登录工具类 - 简化版本(直接从URL获取code)
class WeChatLogin {
constructor() {
......@@ -50,14 +47,24 @@ class WeChatLogin {
}
}
// 获取用户信息 - 使用axios
// 获取用户信息 - 使用fetch
async getUserInfo(code) {
try {
const response = await post('/pedapi/pedService/wxcp/auth', {
authCode: code
const response = await fetch('/pedapi/pedService/wxcp/auth', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
authCode: code
})
})
const result = response.data
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
const result = await response.json()
if (result.code === 0) {
// 保存用户信息
......
......@@ -32,6 +32,7 @@
const userInfo = localStorage.getItem('wechat_user')
const {extMap = {}} = JSON.parse(userInfo || '{}')
const userToken = extMap.sessionId;
console.log('userToken', userToken)
// 使用环境变量代替硬编码
const appCode = import.meta.env.VITE_APP_CODE || 'ped.qywx';
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment