日常解惑-记录一次调试session的问题

前言

利用spring session技术来使用Redis进行session的共享遇到的问题。

业务场景

涉及到三个微服务,分别是登录服务auth,商城主页product和会员服务member。

基本逻辑是这样的:首先到商城主页,然后通过商城主页跳转到登录页面,登录页面通过feign调用member的远程服务对用户进行登录,member服务会通过调用远程数据库来确认账户名密码是否正确,正确的话则会将用户名添加进session,然后会通过重定向跳转到主页,主页通过session取出用户的用户名,并进行显示。

实际开发过程中,发现了如下几个问题:

  1. 放到Redis里面的数据并没有按照希望的json格式进行序列化存储。
  2. 商品主页无法取到session内部放入的用户名。

问题解决

第一个其实蛮好解决的,首先去掉类上面的implements Serializable,然后给容器中增加一个json序列化的东西即可。

第二个问题其实我排查了很久很久。

首先是去确认下是不是我session的域设置的有问题,导致只有auth.mall.com这个子域名能够访问到,而mall.com这个大域名下获取不到session,排查了一下session的域设置的是正确的。

然后又怀疑是不是我数据没放到Redis里面,去看了一眼数据确实放进去了,而且也是正确的json格式。

但是商品服务却怎么也拿不到session里面的数据。最后仔细看了下流程,就在想是不是登录页面通过feign进行远程调用的时候,导致了session的不一致。在代码里增加了session id的打印看了一眼,确实是这个问题。

稍微修改了一下上面的逻辑,不再是由会员服务member直接把用户名放入到session里面,而是通过返回用户名给登录服务auth,由auth放入到session里面,这样能确保主页也能取到。

feign默认情况下,是会构造一个request发送到远端服务器达成代码的调用的,而默认的这个request是不带请求头的,也就是不会携带上JSSEIONID的。解决办法就是手动新增一个拦截器,在拦截器里面为请求头加上jsessionid,就可以了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Configuration
public class FeignConfig {

@Bean
public RequestInterceptor requestInterceptor() {
return new RequestInterceptor() {
@Override
public void apply(RequestTemplate requestTemplate) {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
String cookie = request.getHeader("Cookie");
requestTemplate.header("Cookie", cookie);
}
};
}
}

最后还发生了一个小小的问题:反序列化错误。这个是由于我在auth里面放入session的是一个对象,而在product里面没有,所以稍微修改了一下让auth和product都依赖同一个类,这样序列化和反序列化就没有问题了。