前端加
withCredentials: true
这样前端才会带cookie,这样才能确定这个哪个会话,从而不会每次请求session都不一样了,但这可能会引起跨域,即使前端使用了代理,所以后端要进行配置(允许接收cookie)。
前端:
import axios from 'axios';
import { ElNotification, ElMessageBox, ElMessage } from 'element-plus';
import { getToken, removeToken } from '@/utils/auth.js';
import errorCode from '@/utils/errorCode.js';
import { tansParams } from '@/utils/xavier.js';
import cache from '@/plugins/cache';
// 是否显示重新登录
export let isRelogin = { show: false };
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8';
// 创建axios实例
const service = axios.create({
baseURL: import.meta.env.VITE_GO_URL,
timeout: 5000,
withCredentials: true
});
// request拦截器
service.interceptors.request.use(
(config) => {
// 是否需要设置 token
const isToken = (config.headers || {}).isToken === false;
// 是否需要防止数据重复提交
const isRepeatSubmit = (config.headers || {}).repeatSubmit === false;
if (getToken() && !isToken) {
config.headers['Authorization'] = getToken(); // 让每个请求携带自定义token 请根据实际情况自行修改
}
// get请求映射params参数
if (config.method === 'get' && config.params) {
let url = config.url + '?' + tansParams(config.params);
url = url.slice(0, -1);
config.params = {};
config.url = url;
}
if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
const requestObj = {
url: config.url,
data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
time: new Date().getTime(),
};
const sessionObj = cache.session.getJSON('sessionObj');
if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
cache.session.setJSON('sessionObj', requestObj);
} else {
const s_url = sessionObj.url; // 请求地址
const s_data = sessionObj.data; // 请求数据
const s_time = sessionObj.time; // 请求时间
const interval = 200; // 间隔时间(ms),小于此时间视为重复提交
if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
const message = '数据正在处理,请勿重复提交';
console.warn(`[${s_url}]: ` + message);
return Promise.reject(new Error(message));
} else {
cache.session.setJSON('sessionObj', requestObj);
}
}
}
return config;
},
(error) => {
console.log(error);
Promise.reject(error);
}
);
// 响应拦截器
service.interceptors.response.use(
(res) => {
// 未设置状态码则默认成功状态
const code = res.data.code || 200;
// 获取错误信息
const msg = errorCode[code] || res.data.msg || errorCode['default'];
// 二进制数据则直接返回
if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
return res.data;
}
if (code === 502) {
if (!isRelogin.show) {
isRelogin.show = true;
ElMessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', {
confirmButtonText: '重新登录',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
isRelogin.show = false;
removeToken();
location.href = '/login';
})
.catch(() => {
isRelogin.show = false;
});
} else {
removeToken();
location.href = '/login';
}
return Promise.reject('无效的会话,或者会话已过期,请重新登录。');
} else if (code === 500) {
ElMessage({ message: msg, type: 'error' });
return Promise.reject(new Error(msg));
} else if (code !== 200) {
ElNotification.error({ title: msg });
return Promise.reject('error');
} else {
return Promise.resolve(res.data.data);
}
},
(error) => {
console.log('err' + error);
let { message } = error;
if (message == 'Network Error') {
message = '后端接口连接异常';
} else if (message.includes('timeout')) {
message = '系统接口请求超时';
} else if (message.includes('Request failed with status code')) {
message = '系统接口' + message.substr(message.length - 3) + '异常';
}
ElMessage({ message: message, type: 'error', duration: 5 * 1000 });
return Promise.reject(error);
}
);
export default service;
后端配置:
package com.xavier.pms.config; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component @Slf4j public class SimpleCORSFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletResponse response = (HttpServletResponse) res; HttpServletRequest request = (HttpServletRequest) req; response.setHeader("Access-Control-Allow-Origin", "http://localhost:8888"); response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, HEAD, PUT"); response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Headers", "Origin, Content-Type, Accept, Authorization, X-Requested-With"); response.setHeader("Access-Control-Allow-Credentials", "true"); // 允许发送凭证:当 Access-Control-Allow-Credentials 设置为 true 时,浏览器允许发送请求时携带凭证(如 cookies 和 HTTP 认证信息)。默认情况下,浏览器不会在跨域请求中发送凭证。 if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { response.setStatus(HttpServletResponse.SC_OK); return; } chain.doFilter(req, res); } @Override public void init(FilterConfig filterConfig) {} @Override public void destroy() {} }