[gulimall] cookie写入问题

问题起源

场景1: 在微服务场景下,用户登录是通过认证服务来完成的,登录成功会将sessionId存在cookie中,但是当登录成功跳转到首页时并不能获取到session信息,原因就是首页在另外一个服务中,此时cookie出现了跨域问题获取不到。

场景2: feign远程调用时,也会丢失cookie,因为feign自己构造了一个新的请求,这个请求里面没有任何请求头。在异步编排时,feign还会丢失上下文信息,因为老请求的信息存在threadlocal里,开启多线程时,就获取不到老请求的信息了

cookie写入问题

解决cookie写入问题,要注意两点:

  1. cookie中的domain域必须和地址栏(或者是父域名)一致。
  2. cors跨域满足携带cookie的生效条件
    • 服务的响应头中需要携带Access-Control-Allow-Credentials并且为true。(网关中已设置)
    • 响应头中的Access-Control-Allow-Origin一定不能为*,必须是指定的域名。(网关中已设置具体域名)
    • 浏览器发起ajax需要指定withCredentials 为true。(前端工程:gmall-admin\src\utils\httpRequest.js文件已经设置)

场景1原因

在获取cookie的作用域,也就是getDomainName方法中,其中获取的serverName是ip地址。并不是我们提供的域名

这是因为在地址栏输入域名时,经过了两次转发:

  • 我们使用了nginx反向代理,当监听到www.gulimall.com的时候,会自动将请求转发至代理ip地址,即gateway服务器地址。
  • 而后请求到达我们的gateway网关,gateway网关就会根据路径匹配

而这两次转发都会丢失域名信息。

场景1解决1

写一个session的配置,扩大cookie的作用域,原来的作用域为auth.gulimall.com,现在扩大为gulimall.com

@Configuration
public class GulimallSessionConfig {

    @Bean
    public CookieSerializer cookieSerializer() {

        DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();

        //放大作用域
        cookieSerializer.setDomainName("gulimall.com");
        cookieSerializer.setCookieName("GULISESSION");

        return cookieSerializer;
    }


    @Bean
    public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
        return new GenericJackson2JsonRedisSerializer();
    }

}

解决2

1. nginx转发时要携带域名

需要在nginx配置文件中配置代理头信息:

proxy_set_header Host $host;

修改完成之后,重启nginx

2. 网关转发时要携带域名

在网关转发请求给服务时,要携带地址信息:

spring.cloud.gateway.x-forwarded.host-enabled=true

修改之后再次重启,测试

发现serverName依然时ip地址。

这是因为网关转发后,会把域名通过X-Forwarded-Host头信息转发给服务。所以,需要修改代码,如下:

String serverName = request.getHeader("X-Forwarded-Host");

场景2解决

自定义feign的拦截器,给新请求同步老请求的cookie


@Configuration
public class GuliFeignConfig {

    @Bean("requestInterceptor")
    public RequestInterceptor requestInterceptor() {

        RequestInterceptor requestInterceptor = new RequestInterceptor() {
            @Override
            public void apply(RequestTemplate template) {
                //1、使用RequestContextHolder拿到刚进来的请求数据
                ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

                if (requestAttributes != null) {
                    //老请求
                    HttpServletRequest request = requestAttributes.getRequest();

                    if (request != null) {
                        //2、同步请求头的数据(主要是cookie)
                        //把老请求的cookie值放到新请求上来,进行一个同步
                        String cookie = request.getHeader("Cookie");
                        template.header("Cookie", cookie);
                    }
                }
            }
        };

        return requestInterceptor;
    }

}

异步编排时,每一个线程都来共享之前的请求数据

//先拿到老请求的信息
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

        //第一个异步任务
        CompletableFuture<Void> addressFuture = CompletableFuture.runAsync(() -> {

            //每一个线程都来共享之前的请求数据
            RequestContextHolder.setRequestAttributes(requestAttributes);
            List<MemberAddressVo> address = memberFeignService.getAddress(memberResponseVo.getId());
            confirmVo.setMemberAddressVos(address);
        }, threadPoolExecutor);

        //第二个异步任务
        CompletableFuture<Void> cartInfoFuture = CompletableFuture.runAsync(() -> {

            //每一个线程都来共享之前的请求数据
            RequestContextHolder.setRequestAttributes(requestAttributes);
            List<OrderItemVo> currentCartItems = cartFeignService.getCurrentCartItems();
            confirmVo.setItems(currentCartItems);
        }, threadPoolExecutor);
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值