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里面添加

#主意這個需要在你每個注冊到網關的服務上面都要添加一個這個
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;
    }
}

 

好了,基本上就是這樣子,這個問題,我也是糾結了一天,總結下來,希望可以幫到以后的你們


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM