记一次Spring Cloud Session微服务间传递丢失问题定位 - 乱炖 - CSDN博客

       在构建基于Spring Cloud微服务框架时,使用了常用的框架NGINX+ZUUL+Eureka+业务服务,Session使用Spring boot的Redis集成,所有微服务间共享Session

    所有业务的微服务Rest接口前台调用接口通过ZUUL进行转发,而ZUUL通过创建ZUULFilter过滤器来对请求鉴权及一些Session操作,而且为了保证Session实时生效,故设置Spring boot的Redis Session声明为立即生效,如下所示:

    @EnableRedisHttpSession(redisFlushMode = RedisFlushMode.IMMEDIATE)

   在第一次业务请求时ZUUL过滤器会创建Session并设置属性,然后直接将请求转发到业务服务,

@Componentpublic class LoginFilter extends ZuulFilter {      private final static Logger LOG = LoggerFactory.getLogger(LoginFilter.class);        @Override    public Object run() throws ZuulException {        Double rand = Math.random() * 100;        int randInt = rand.intValue();        RequestContext ctx = RequestContext.getCurrentContext();        HttpServletResponse response = ctx.getResponse();        HttpServletRequest request = ctx.getRequest();        HttpSession session = request.getSession();        session.setAttribute("test", randInt);                LOG.info("Session id:{} test:{}",session.getId(),randInt);        return null;    }      @Override    public boolean shouldFilter() {        return true;    }      @Override    public int filterOrder() {        return 0;    }      @Override    public String filterType() {        return "pre";    } }

   然而业务服务在调用方法时通过request.getSession(false)获取的Session为null,但紧接着第二次及后续调用时业务服务都能获取到了正确的Session。

@RestControllerpublic class BusinessController {        private final static Logger LOG = LoggerFactory.getLogger(BusinessController.class);        @RequestMapping(path="/getsession/{key}")    public String getSessionVal(HttpServletRequest request,@PathVariable("key") String key) {        HttpSession session = request.getSession(false);        Object value = null;        if(null != session) {            value = session.getAttribute(key);        }        LOG.info("Session id:{} value:{}",session == null ? null:session.getId(),value);        return "";    } }

    这么奇葩的现象,第一次Session创建成功居然Session不能传递,实在是令人匪夷所思

    由于没有特殊定制过Spring boot Session机制,都是使用默认的Cookie传递方式。业务服务获取不到Session,有两种可能,一种是Redis没有实时创建Session对象,另外一种是业务不能通过SESSIONID获取到对象。

    通过Debug断点定位,在ZUUL创建Session时,通过Redis客户端,直接连接到Redis服务器,查看发现Redis实时的生成了Session对象,故第一个假设应该不成立的。

   然后通过打印在ZUUL与业务服务中Request Cookie信息,发现ZUUL在创建完Session后,并没有更新request的Cookie中的SESSIONID,且request.isRequestedSessionIdValid()为false,故业务第一次获取到的request中的Cookie没有新的SESSIONID,就更不能根据Cookie获取Session了,第二种假设成立。

    通过查询资料,明白了只有在请求Response响应后请求的Cookie才会更新,第一次请求时创建的Session不会在微服务间进行传递。天真的认为可以宽心的使用Spring cloud全家桶,殊不知还是需要细心与思考,同时也许需要知识积累。

    从单体引用根本不会出现这种情况,Session在一个服务中传递,不存在Session重新通过Cookie获取。而微服务简化了业务,但多了交互,外部交流越多,越容易出错,也许在微服务的路上还有更多的坑需要填补。

    如何填补这个坑呢?

   下次再进行分析~~


Original url: Access
Created at: 2019-03-07 23:34:33
Category: default
Tags: none

请先后发表评论
  • 最新评论
  • 总共0条评论