springcloud使用zull+redis+spring-session实现session共享,及解决ajax请求session不共享的坑

1.首先在相应的pom.xml中导入redis的依赖

1  <!--添加redis-->
2         <dependency>
3             <groupId>org.springframework.boot</groupId>
4             <artifactId>spring-boot-starter-data-redis</artifactId>
5         </dependency>
6         <dependency>
7             <groupId>org.springframework.session</groupId>
8             <artifactId>spring-session-data-redis</artifactId>
9         </dependency>

2.在application.properties里添加redis的配置信息

 1 #添加redis
 2 spring.redis.database=0
 3 spring.redis.host=localhost
 4 spring.redis.port=6379
 5 spring.redis.password=123456
 6 spring.redis.timeout=20000ms
 7 spring.redis.jedis.pool.max-active=8
 8 spring.redis.jedis.pool.max-wait=-1ms
 9 spring.redis.jedis.pool.max-idle=8
10 spring.redis.jedis.pool.min-idle=0

3.在启动类里面添加注解

@SpringBootApplication
@EnableRedisHttpSession(flushMode = FlushMode.IMMEDIATE)
public class UserServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}

4.需要在网关中定义服务的头信息过滤规则,zuul默认会将头信息全部过滤掉,这会导致cookie丢失,就无法从redis中取出session数据了。

在网关的application.properties里面添加

#需要忽略的头部信息,不在传播到其他服务
sensitive-headers: Access-Control-Allow-Origin
ignored-headers: Access-Control-Allow-Origin,H-APP-Id,Token,APPToken
#主意这个需要在你每个注册到网关的服务上面都要添加一个这个
zuul.routes.服务名称.sensitiveHeaders="*"
 

5.存session和取session的过程,spring帮我们自动的取完成了,存session

 public Result ifLogin(HttpSession session) {
    //存session,spring自动帮我们存取到redis中
    session.setAttribute("user", user1);
    //取session
    session.getAttribute("user");
}        

到这里基本就可以实现session在不同服务间的session共享了,如果不能,请往下看

  • 第一种解决方案直接存在redis里面,然后在不同服务间直接去取
  • @Autowired
     private RedisTemplate redisTemplate;
    @RequestMapping("login")
      public String login(){
        //直接将session存入到redis中
        redisTemplate.opsForValue().set("user",user);
       //然后取
      redisTemplate.opsForValue().get("user");       
    }

注意:如果你是使用ajax来发送请求,你发现不管怎么样,session都共享不了,即使在同一个controller的不同请求之间,session都共享不了,那么你需要设置以下:

//使用原生的ajax 
$.ajax({
            url: "http://localhost:8080/orders",
            type: "GET",
//这里是重点
            xhrFields: {
                withCredentials: true
            },
            crossDomain: true,
            success: function (data) {
                render(data);
            }
 });
如果使用的是$.post("http://192.168.10.*/user/user/ifLogin",callback,"json")
还需设置ajax全局发送请求的方式,带上请求头,和原生的自己比较便知
$(function(){
    $.ajaxSetup({xhrFields: {
            withCredentials: true
        }})
})
  • 另外还需在zuul网关里面设置一下配置
@Configuration
public class CorsConfig {
    @Bean
    public CorsFilter corsFilter() {
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true); // 允许cookies跨域
        config.addAllowedOrigin("*");// #允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin
        config.addAllowedHeader("*");// #允许访问的头信息,*表示全部
        config.setMaxAge(7200L);// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了
        config.addAllowedMethod("*");// 允许提交请求的方法,*表示全部允许
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
}
package com.study.zuul.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Configuration
public class FirstFilter extends ZuulFilter {
    /**
     * pre:可以在请求被路由之前调用
     * route:在路由请求时候被调用
     * post:在route和error过滤器之后被调用
     * error:处理请求时发生错误时被调用
     *
     * @return
     */
    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

    /**
     * 优先级为0,数字越大,优先级越低
     *
     * @return
     */
    @Override
    public int filterOrder() {
        return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletResponse response = ctx.getResponse();
        HttpServletRequest request = ctx.getRequest();
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH");
        response.setHeader("Access-Control-Allow-Headers", "x-access-token, content-type");
        response.setHeader("Access-Control-Expose-Headers", "X-forwared-port, X-forwarded-host");
        response.setHeader("Vary", "Origin,Access-Control-Request-Method,Access-Control-Request-Headers");
        // 跨域请求一共会进行两次请求 先发送options 是否可以请求
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            ctx.setSendZuulResponse(false); //验证请求不进行路由
            ctx.setResponseStatusCode(HttpStatus.OK.value());//返回验证成功的状态码
            return null;
        }
        ctx.setSendZuulResponse(true); //对请求进行路由
        ctx.setResponseStatusCode(HttpStatus.OK.value());
        return null;
    }
}

好了,基本上就是这样子,这个问题,我也是纠结了一天,总结下来,希望可以帮到以后的你们

猜你喜欢

转载自www.cnblogs.com/nukill/p/11853591.html