【记一次采坑】Spring 微服务调用session失效

用Spring 微服务架构开发时,微服务之间相互调用时,需要传递sessionId以识别请求用户。
例如用户请求A服务,A服务调用B服务;在A调用B的时候,需要将用户的sessionId传递给B,让B知道是哪个用户在访问。
微服务之间的相互调用我们使用的时Feign,为了传递sessionId,我们定义了一个RequestInterceptor,用来添加sessionId,代码如下

public class FeignRequestIntercepter implements RequestInterceptor {

  @Override
  public void apply(RequestTemplate requestTemplate) {
    RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
    if (requestAttributes == null) {
      return;
    }
    HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
    String sessionId = request.getSession().getId();
    log.info("Long feign intercepter session id is " + sessionId);
    if (sessionId != null) {
      requestTemplate.header("Cookie", "SESSION=" + sessionId);
    }
  }
}

这个办法在升级Spring版本之前是OK的,升级Spring后发现失效了。本以为是设置的header没有传到B,于是自定义了一个header放到requestTemplate里。经过debug代码,发现B是可以收到自定义的header的,接着又推测是sessionId被spring覆盖了,于是继续折腾debug。。。。突然,发现一个奇怪的问题:B服务里,HttpServletRequest 的getSession().getId()方法返回的sessionId和HttpServletRequest.getCookies得到的sessionId不一样

于是朝着这两个方法的代码查看,最后发现spring升级后,cookie里的SESSION是对sessionId使用的base64编码后的值。这么做是rfc协议最新的建议。修改代码如下后搞定

public void apply(RequestTemplate requestTemplate) {
  RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
  if (requestAttributes == null) {
    return;
  }
  HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
  String sessionId = request.getSession().getId();
  if (sessionId != null) {
    requestTemplate.header("Cookie", "SESSION=" + base64Encode(request.getSession().getId()));
  }
}

public static String base64Encode(String value) {
    byte[] encodedCookieBytes = Base64.getEncoder().encode(value.getBytes());
    return new String(encodedCookieBytes);
}

你可能感兴趣的:(应用开发)