1.发现问题
刚学完vue2自己做了一个前段项目练练手,但是没有学vue2的反向代理
我遇到这个问题就是因为在后端为了实现createTime createBy updateTime updateBy等字段的自动填充,自己写了连个类
一个是MyMetaObjectHandler
package com.viego.financialrecommendsystem.common;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Date;
/**
* 源数据处理器
*/
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
/**
* 插入自动填充
* @param metaObject 填充对象
*/
@Override
public void insertFill(MetaObject metaObject) {
Long currentId = BaseContext.getCurrentId();
log.info("公共字段自动填充中【insert】");
log.info(metaObject.toString());
log.info("已从BaseContext中获取到当前的UID,UID = {}",currentId);
metaObject.setValue("updateTime", new Date());
metaObject.setValue("updateBy",currentId);
metaObject.setValue("createTime",new Date());
metaObject.setValue("createBy",currentId);
}
/**
* 更新自动填充
* @param metaObject 填充对象
*/
@Override
public void updateFill(MetaObject metaObject) {
Long currentId = BaseContext.getCurrentId();
log.info("公共字段自动填充中【update】");
log.info(metaObject.toString());
log.info("已从BaseContext中获取当前的UID,UID={}",currentId);
metaObject.setValue("updateTime",LocalDateTime.now());
metaObject.setValue("updateBy",currentId);
}
}
其次还有一个BaseContext类
package com.viego.financialrecommendsystem.common;
/**
* 基于ThreadLocal封装的工具类,用户保存或获取当前登录用户的ID
*/
public class BaseContext {
private static ThreadLocal<Long> threadLocal=new InheritableThreadLocal<>();
public static void setCurrentId(Long id){
threadLocal.set(id);
}
public static Long getCurrentId(){
return threadLocal.get();
}
}
因为用到了这个Thread线程所以,我们需要使用过滤器,Filter
之后我又写了一个过滤器
package com.viego.financialrecommendsystem.filter;
import com.alibaba.druid.support.json.JSONUtils;
import com.viego.financialrecommendsystem.common.AjaxResult;
import com.viego.financialrecommendsystem.common.BaseContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 检查用户是否应完成登录的过滤器
*/
// urlPatterns="/*"表示次拦截器,要眼界所有路径的请求
@WebFilter(filterName = "loginCheckFilter",urlPatterns = "/*")
@Slf4j
public class LoginCheckFilter implements Filter {
//路径配置器,支持通配符
public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpServletRequest request = (HttpServletRequest) servletRequest;
log.info("拦截到请求:{}",request.getRequestURI());
/**
* 1.获取本次请求的URL
* 2.判断你本次请求是否需要处理
* 3.如果不需要处理,则直接放行
* 4.判断登录状态,如果已经登录,则放行
* 5.如果未登录,则返回未登录的结果
*/
//1.获取本次请求
String requestURI = request.getRequestURI();
String[] urls = {
"/FinancialRecommend/user/login",
"/FinancialRecommend/user/logout",
"/FinancialRecommend/img/**",
};
//2.判断本次请求是否需要处理
boolean check = check(urls, requestURI);
//3.如果不需要处理,则直接放行
if (check){
//匹配成功,不需要不处理直接放行
log.info("本次请求不需要处理:{}",requestURI);
filterChain.doFilter(servletRequest,servletResponse);
}else{
//匹配失败,需要法处理,进行拦截
log.info("本次请求需要处理:{}",request);
Object uid = request.getSession().getAttribute("UID");
if (uid != null){
//用户已经登录直接放行
log.info("已登录,放行");
log.info("用户的 UID = {}",uid);
BaseContext.setCurrentId((Long)uid );
filterChain.doFilter(servletRequest, servletResponse);
return;
}else{
//用户没有登录,通过输出流的燃放时,向前端返回数据
log.info("用户未登录,向客户端返回NOTLOGIN");
response.getWriter().write(JSONUtils.toJSONString(AjaxResult.error("NOTLOGIN")));
}
}
}
/**
* 封装的静态方法
* 判断请求是否需要处理
* @param urls 需要处理的请求的数组
* @param requestURI 当前请求的URL
* @return 需要处理 true 不需要处理 false
*/
public boolean check(String[] urls,String requestURI){
for (String url : urls) {
boolean match = PATH_MATCHER.match(url, requestURI);
if (match){
//匹配成功
return true;
}
}
//匹配失败
return false;
}
}
2.思考问题
但是当我登录成功后,再次访问其他请求时,获取到的session都是和上次不一样,而在正常情况下,应该是一样的才对,可以拿出我登录时保存的UID,所以,问题在,为什么我每一次请求拿到的session都是不一样的,我接着继续思考。首先,我想到的一种情况就是,之前的session被销毁了,之后我就有自己设置了一下session的自动销毁时间,把所有的问题都拍出来,但是这个问题还是没有解决。
之后我就直接问的ChatGPT,
因为我这个项目是启动的两个服务,所以前段请求后端都是跨域请求,而如果前段不设置反向代理的话,每一次请求都是一次新的回话,也就是说,每一次请求的session都是不一样的,所以才导致了这个问题的产生,因此,我接着有在我的前端项目中做了一个反向代理
3.解决问题
下面是我的反向代理代码
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true
})
module.exports = {
devServer: {
proxy: {
'/FinancialRecommend': {
target: 'http://localhost:8888',//代理的目标地址
changeOrigin: true,//是否改变请求源地址
PathRewrite: {
'^/FinancialRecommend': '/FinancialRecommend'//重写请求路径,将api代替为FinancialRecommend
}
}
}
}
}
加上这个代理了之后,我又在每一个组件中添加了这段代码
import axios from "axios";
axios.defaults.withCredentials = true
到了这个,这个问题也就解决了,因为我是第一次做这样的前后端分离项目,所以我也第一次做反向代理,我以前要做跨域请求的处理,都是在后端,因为我也更熟悉后端嘿嘿~~~
4.总结问题
在前后端分离的项目中,因为,前段和后端都是不通项目,所以会出现跨域请求的问题,这个问题该怎么解决,我们在前后端都需配置,前段需要看你用的什么框架(在这里我用的是Vue2)所以我就做了vue2的反向代理,然后后端就简单的做了一个,允许所有请求访问。至此,问题就都解决了。