Springcloud分布式服务如何保证会话一致性
在Springcloud分布式项目中,服务与服务之间调用是非常常见的。有时候服务与服务间调用的时候涉及到用户的身份,比如当前登录的用户的身份获取与传递。
在之前boot单体应用前后端分离的时候,常见的两种方式,一种是基于session机制+nginx代理;另一种是基于token,也就是每个请求的header中携带token,token的值就是当前登录的标识,可以是后端返回的一个UUID,该UUID对应redis的一个key,每次访问根据UUID从redis获取到当前用户的信息。
1. sessionId不一致问题
基于feign调用的sessionId不一致问题。
1. 被调用方controller(payment服务)
@GetMapping("/getSessionId") public JSONResultUtil<Map<String, Object>> getSessionId() { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()) .getRequest(); String id = sessionId(); System.out.println(id); Cookie[] cookies = request.getCookies(); if (ArrayUtils.isNotEmpty(cookies)) { System.out.println("====S cookie"); for (Cookie cookie : cookies) { System.out.println(cookie.getName() + "\t" + cookie.getValue()); } System.out.println("====E cookie"); } Enumeration<String> headerNames = request.getHeaderNames(); System.out.println("====S header"); while (headerNames.hasMoreElements()) { String s = headerNames.nextElement(); System.out.println(s + "\t" + request.getHeader(s)); } System.out.println("====E header"); HashMap<String, Object> stringObjectHashMap = new HashMap<>(); stringObjectHashMap.put("payment", id); return JSONResultUtil.successWithData(stringObjectHashMap); } public String sessionId() { RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); if (requestAttributes == null) { return null; } HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest(); return request.getSession().getId(); }
2.调用方(order服务)
1.Controller
/************s 测试获取sessionId*********/ @GetMapping("/getSessionId") public JSONResultUtil<Map<String, Object>> getSessionId() { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()) .getRequest(); String id = sessionId(); System.out.println(id); Cookie[] cookies = request.getCookies(); if (ArrayUtils.isNotEmpty(cookies)) { System.out.println("====S cookie"); for (Cookie cookie : cookies) { System.out.println(cookie.getName() + "\t" + cookie.getValue()); } System.out.println("====E cookie"); } Enumeration<String> headerNames = request.getHeaderNames(); System.out.println("====S header"); while (headerNames.hasMoreElements()) { String s = headerNames.nextElement(); System.out.println(s + "\t" + request.getHeader(s)); } System.out.println("====E header"); HashMap<String, Object> stringObjectHashMap = new HashMap<>(); stringObjectHashMap.put("order", id); Map<String, Object> data = paymentHystrixService.getSessionId().getData(); stringObjectHashMap.putAll(data); return JSONResultUtil.successWithData(stringObjectHashMap); } public String sessionId() { RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); if (requestAttributes == null) { return null; } HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest(); return request.getSession().getId(); } /************E 测试获取sessionId*********/
2.Feign接口
package cn.qz.cloud.service; import cn.qz.cloud.utils.JSONResultUtil; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import java.util.Map; /** * @Author: qlq * @Description * @Date: 14:31 2020/10/18 */ @Component // 只调用,不降级。 @FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT") //@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT", fallback = PaymentFallbackService.class) public interface PaymentHystrixService { @GetMapping("/hystrix/payment/getSessionId") JSONResultUtil<Map<String, Object>> getSessionId(); }
3. 启动后测试
1.访问接口
liqiang@root MINGW64 /e/IDEAWorkSpace/cloud (master) $ curl http://localhost:8011//consumer/hystrix/payment/getSessionId % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 139 0 139 0 0 1275 0 --:--:-- --:--:-- --:--:-- 1782{"success":true,"code":"200","msg":"","data":{"payment":"30e4e45e-258e-499f-9170-e9c7e0f4acb7","order":"6A261DF8C0CBFB3867FA1DE3A785D7FA"}}
2.order服务日志
6A261DF8C0CBFB3867FA1DE3A785D7FA ====S header host localhost:8011 user-agent curl/7.54.1 accept */* ====E header
3. payment日志
30e4e45e-258e-499f-9170-e9c7e0f4acb7 ====S header accept */* user-agent Java/1.8.0_121 host root:8081 connection keep-alive ====E header
可以看到两个服务的sessionId不一样。
2. 引入Spring-session解决会话共享-session信息存入redis
用第一个服务payment服务测试。
1.pom增加
<!--session 共享--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-redis</artifactId> <version>1.4.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency>
2.yml增加配置
spring:
application:
name: cloud-provider-hystrix-payment
redis:
port: 6379
host: localhost
session:
store-type: redis
上面关于redis合session的配置也是默认的配置,可以参考:org.springframework.boot.autoconfigure.session.SessionProperties 和 org.springframework.boot.autoconfigure.data.redis.RedisProperties。
3. 修改Controller
@GetMapping("/getSessionId") public JSONResultUtil<Map<String, Object>> getSessionId() { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()) .getRequest(); // 模拟当前用户登录 zs 存进去 request.getSession().setAttribute("currentUser", "zs"); String id = sessionId(); System.out.println(id); Cookie[] cookies = request.getCookies(); if (ArrayUtils.isNotEmpty(cookies)) { System.out.println("====S cookie"); for (Cookie cookie : cookies) { System.out.println(cookie.getName() + "\t" + cookie.getValue()); } System.out.println("====E cookie"); } Enumeration<String> headerNames = request.getHeaderNames(); System.out.println("====S header"); while (headerNames.hasMoreElements()) { String s = headerNames.nextElement(); System.out.println(s + "\t" + request.getHeader(s)); } System.out.println("====E header"); HashMap<String, Object> stringObjectHashMap = new HashMap<>(); stringObjectHashMap.put("payment", id); stringObjectHashMap.put("paymentCurrentUser", request.getSession().getAttribute("currentUser")); return JSONResultUtil.successWithData(stringObjectHashMap); } public String sessionId() { RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); if (requestAttributes == null) { return null; } HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest(); return request.getSession().getId(); }
4.测试:
1.curl:
$ curl http://localhost:8081/hystrix/payment/getSessionId % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 122 0 122 0 0 748 0 --:--:-- --:--:-- --:--:-- 753{"success":true,"code":"200","msg":"","data":{"paymentCurrentUser":"zs","payment":"a8547342-c959-4209-a964-b58f60585a10"}}
2.控制台日志如下:
a8547342-c959-4209-a964-b58f60585a10 ====S header host localhost:8081 user-agent curl/7.71.1 accept */* ====E header
3. 用浏览器访问查看返回的响应头如下:
可以看到,返回的setcookie中SESSION为:ZmViZjBkM2YtNGQ5Zi00ZGU3LThjZjAtNDE3MzgxNWNmZDhj。 SESSION也是Spring-session存sessionId的name,tomcat默认的为JSESSIONID。
程序控制台日志如下:
febf0d3f-4d9f-4de7-8cf0-4173815cfd8c ====S cookie sensorsdata2015jssdkcross %7B%22distinct_id%22%3A%2217608e35e0b169-09416062df57be-51a2f73-1327104-17608e35e0c18d%22%2C%22%24device_id%22%3A%2217608e35e0b169-09416062df57be-51a2f73-1327104-17608e35e0c18d%22%2C%22props%22%3A%7B%22%24latest_referrer%22%3A%22url%E7%9A%84domain%E8%A7%A3%E6%9E%90%E5%A4%B1%E8%B4%A5%22%2C%22%24latest_referrer_host%22%3A%22url%E7%9A%84domain%E8%A7%A3%E6%9E%90%E5%A4%B1%E8%B4%A5%22%2C%22%24latest_traffic_source_type%22%3A%22url%E7%9A%84domain%E8%A7%A3%E6%9E%90%E5%A4%B1%E8%B4%A5%22%2C%22%24latest_search_keyword%22%3A%22url%E7%9A%84domain%E8%A7%A3%E6%9E%90%E5%A4%B1%E8%B4%A5%22%7D%7D ====E cookie ====S header accept text/html, application/xhtml+xml, image/jxr, */* accept-language zh-Hans-CN,zh-Hans;q=0.5 user-agent Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko accept-encoding gzip, deflate host 127.0.0.1:8081 connection Keep-Alive cookie sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%2217608e35e0b169-09416062df57be-51a2f73-1327104-17608e35e0c18d%22%2C%22%24device_id%22%3A%2217608e35e0b169-09416062df57be-51a2f73-1327104-17608e35e0c18d%22%2C%22props%22%3A%7B%22%24latest_referrer%22%3A%22url%E7%9A%84domain%E8%A7%A3%E6%9E%90%E5%A4%B1%E8%B4%A5%22%2C%22%24latest_referrer_host%22%3A%22url%E7%9A%84domain%E8%A7%A3%E6%9E%90%E5%A4%B1%E8%B4%A5%22%2C%22%24latest_traffic_source_type%22%3A%22url%E7%9A%84domain%E8%A7%A3%E6%9E%90%E5%A4%B1%E8%B4%A5%22%2C%22%24latest_search_keyword%22%3A%22url%E7%9A%84domain%E8%A7%A3%E6%9E%90%E5%A4%B1%E8%B4%A5%22%7D%7D ====E header
注意:
(1)这里发行程序打出的会话ID,sessionId为:febf0d3f-4d9f-4de7-8cf0-4173815cfd8c,而程序返回给设置Cookie头的是:ZmViZjBkM2YtNGQ5Zi00ZGU3LThjZjAtNDE3MzgxNWNmZDhj。其实ZmViZjBkM2YtNGQ5Zi00ZGU3LThjZjAtNDE3MzgxNWNmZDh 是base64 编码之后的,我们经过base64 解码后就是febf0d3f-4d9f-4de7-8cf0-4173815cfd8c,这也是Spring-session 默认做的操作。 可以参考类:org.springframework.session.web.http.DefaultCookieSerializer。
(2)到redis查看如下:
127.0.0.1:6379> keys * 1) "spring:session:sessions:expires:febf0d3f-4d9f-4de7-8cf0-4173815cfd8c" 2) "spring:session:expirations:1610786700000" 3) "spring:session:sessions:febf0d3f-4d9f-4de7-8cf0-4173815cfd8c" 127.0.0.1:6379> hget spring:session:sessions:febf0d3f-4d9f-4de7-8cf0-4173815cfd8c (error) ERR wrong number of arguments for 'hget' command 127.0.0.1:6379> keys * 1) "spring:session:sessions:expires:febf0d3f-4d9f-4de7-8cf0-4173815cfd8c" 2) "spring:session:expirations:1610786700000" 3) "spring:session:sessions:febf0d3f-4d9f-4de7-8cf0-4173815cfd8c" 127.0.0.1:6379> hlen spring:session:sessions:febf0d3f-4d9f-4de7-8cf0-4173815cfd8c (integer) 4 127.0.0.1:6379> hgetall spring:session:sessions:febf0d3f-4d9f-4de7-8cf0-4173815cfd8c 1) "maxInactiveInterval" 2) "\xac\xed\x00\x05sr\x00\x11java.lang.Integer\x12\xe2\xa0\xa4\xf7\x81\x878\x02\x00\x01I\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\a\b" 3) "lastAccessedTime" 4) "\xac\xed\x00\x05sr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01w\nBDs" 5) "creationTime" 6) "\xac\xed\x00\x05sr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01w\nBDs" 7) "sessionAttr:currentUser" 8) "\xac\xed\x00\x05t\x00\x02zs"
可以看到存到session中的属性也被存储到redis中
补充:如果想去掉base编码或者修改cookie中session的名称,可以用手动注入一个CookieSerializer,亲测有效
package cn.qz.cloud.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.session.web.http.CookieSerializer; import org.springframework.session.web.http.DefaultCookieSerializer; /** * @author: 乔利强 * @date: 2021/1/16 16:29 * @description: */ @Configuration public class SpringSessionConfiguration { @Bean public CookieSerializer defaultCookieSerializer() { DefaultCookieSerializer defaultCookieSerializer = new DefaultCookieSerializer(); defaultCookieSerializer.setUseBase64Encoding(false); defaultCookieSerializer.setCookieName("mysession"); return defaultCookieSerializer; } }
测试:访问后返回的响应头如下:
这种做法是Spring在自动注入的时候留了个入口:参考类:org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration。 自动注入的时候非必须,在代码中判断注入的为null就使用默认配置。
补充:Spring-session封装了session,同时抽取了操作的工具类
1.接口如下:
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package org.springframework.session; public interface SessionRepository<S extends Session> { S createSession(); void save(S var1); S findById(String var1); void deleteById(String var1); }
2.测试:
@Autowired private SessionRepository sessionRepository; @GetMapping("/test") public void test() { Session byId = sessionRepository.findById(sessionId()); System.out.println(ToStringBuilder.reflectionToString(byId, ToStringStyle.MULTI_LINE_STYLE)); }
3.访问后控制台如下:
org.springframework.session.data.redis.RedisIndexedSessionRepository$RedisSession@a2fcd88[
cached=org.springframework.session.MapSession@a2aeb552
originalLastAccessTime=2021-01-16T08:49:30.766Z
delta={}
isNew=false
originalPrincipalName=<null>
originalSessionId=5fddf9ec-53fe-4f73-8205-7d3a3f9431a8
]
3. Order调用者服务配置Feign调用的时候携带请求头,可以做到session共享
1.修改被调用者服务payment
@GetMapping("/getSessionId") public JSONResultUtil<Map<String, Object>> getSessionId() { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()) .getRequest(); String id = sessionId(); System.out.println(id); Cookie[] cookies = request.getCookies(); if (ArrayUtils.isNotEmpty(cookies)) { System.out.println("====S cookie"); for (Cookie cookie : cookies) { System.out.println(cookie.getName() + "\t" + cookie.getValue()); } System.out.println("====E cookie"); } Enumeration<String> headerNames = request.getHeaderNames(); System.out.println("====S header"); while (headerNames.hasMoreElements()) { String s = headerNames.nextElement(); System.out.println(s + "\t" + request.getHeader(s)); } System.out.println("====E header"); HashMap<String, Object> stringObjectHashMap = new HashMap<>(); stringObjectHashMap.put("payment", id); stringObjectHashMap.put("paymentCurrentUser", request.getSession().getAttribute("currentUser")); return JSONResultUtil.successWithData(stringObjectHashMap); } public String sessionId() { RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); if (requestAttributes == null) { return null; } HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest(); return request.getSession().getId(); }
2.修改调用者Order
1.修改Controller
/************s 测试获取sessionId*********/ @GetMapping("/getSessionId") public JSONResultUtil<Map<String, Object>> getSessionId() { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()) .getRequest(); // 模拟登录成功之后存user信息 request.getSession().setAttribute("currentUser", "张三"); String id = sessionId(); System.out.println(id); HashMap<String, Object> stringObjectHashMap = new HashMap<>(); stringObjectHashMap.put("order", id); stringObjectHashMap.put("orderCurrentUser", request.getSession().getAttribute("currentUser")); Map<String, Object> data = paymentHystrixService.getSessionId().getData(); stringObjectHashMap.putAll(data); return JSONResultUtil.successWithData(stringObjectHashMap); } public String sessionId() { RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); if (requestAttributes == null) { return null; } HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest(); return request.getSession().getId(); } /************E 测试获取sessionId*********/
2.修改Feign调用的时候增加header(实际cookie也是在header中传递的,header的key为cookie)
package cn.qz.cloud.config; import com.google.common.collect.Lists; import feign.Logger; import feign.RequestInterceptor; import feign.RequestTemplate; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.util.*; /** * @author: 乔利强 * @date: 2020/12/30 20:35 * @description: */ @Configuration @Slf4j public class FeignConfiguration { public final static String HEADER_CALLER = "cloud_caller"; public final static String COOKIE_COOKIE_NAME = "cookie"; public final static String SESSIONID_COOKIE_NAME = "SESSION"; @Value("${spring.application.name}") String application; // 对系统中允许后向传递的头进行控制 private static List<String> disallowhHeaderNames = Lists.newArrayList( "cache-control" , "origin" , "upgrade-insecure-requests" , "user-agent" , "referer" , "accept" , "accept-language" , "connection" ); @Bean public RequestInterceptor requestHeaderInterceptor() { return new RequestInterceptor() { @Override public void apply(RequestTemplate requestTemplate) { //记录调用方信息 requestTemplate.header(HEADER_CALLER, application); if (RequestContextHolder.getRequestAttributes() == null) { return; } // 注意子线程问题(RequestContextHolder 内部使用的是ThreadLocal) HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()) .getRequest(); // 当前请求携带的header Enumeration<String> headerNames = request.getHeaderNames(); // 已经存在feign的requestTemplate的header Map<String, Collection<String>> headers = requestTemplate.headers(); if (headerNames != null) { while (headerNames.hasMoreElements()) { String name = headerNames.nextElement(); boolean exists = false; // 避免重复header往后传播,如content-type传播会影响后续body解析 for (String th : headers.keySet()) { if (name.equalsIgnoreCase(th)) {// 忽略大小写 exists = true; break; } } if (!exists && !disallowhHeaderNames.contains(name.toLowerCase())) { requestTemplate.header(name, Collections.list(request.getHeaders(name))); } } } } }; } private String sessionId() { RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); if (requestAttributes == null) { return null; } HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest(); return request.getSession().getId(); } @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } /** * 自定义feignlogger * * @return */ @Bean public feign.Logger feignLogger() { return new FeignLogger(); } }
3.测试
1. 访问http://localhost:8011/consumer/hystrix/payment/getSessionId, 返回结果如下:
{"success":true,"code":"200","msg":"","data":{"orderCurrentUser":"张三","paymentCurrentUser":"张三","payment":"53972a2b-9324-4078-8446-268e13071f06","order":"53972a2b-9324-4078-8446-268e13071f06"}}
2.查看控制台日志如下:
(1)order 调用者
53972a2b-9324-4078-8446-268e13071f06 2021-01-16 23:06:18.022 INFO 16260 --- [nio-8011-exec-5] cn.qz.cloud.config.FeignLogger : [PaymentHystrixService#getSessionId] GET http://CLOUD-PROVIDER-HYSTRIX-PAYMENT/hystrix/payment/getSessionId HTTP/1.1, log request begin. <--- 2021-01-16 23:06:18.023 INFO 16260 --- [nio-8011-exec-5] cn.qz.cloud.config.FeignLogger : [PaymentHystrixService#getSessionId] ---> GET http://CLOUD-PROVIDER-HYSTRIX-PAYMENT/hystrix/payment/getSessionId HTTP/1.1 2021-01-16 23:06:18.023 INFO 16260 --- [nio-8011-exec-5] cn.qz.cloud.config.FeignLogger : [PaymentHystrixService#getSessionId] accept-encoding: gzip, deflate, br 2021-01-16 23:06:18.024 INFO 16260 --- [nio-8011-exec-5] cn.qz.cloud.config.FeignLogger : [PaymentHystrixService#getSessionId] cloud_caller: order80 2021-01-16 23:06:18.024 INFO 16260 --- [nio-8011-exec-5] cn.qz.cloud.config.FeignLogger : [PaymentHystrixService#getSessionId] cookie: Idea-599589ea=7e4185c4-b2de-45e1-9f54-6ae34bfbe678; Webstorm-e34e7d83=831b2048-d1c1-45e6-b4e2-77d667e3f1c4; Hm_lvt_b393d153aeb26b46e9431fabaf0f6190=1605535026; SESSION=NTM5NzJhMmItOTMyNC00MDc4LTg0NDYtMjY4ZTEzMDcxZjA2 2021-01-16 23:06:18.025 INFO 16260 --- [nio-8011-exec-5] cn.qz.cloud.config.FeignLogger : [PaymentHystrixService#getSessionId] host: localhost:8011 2021-01-16 23:06:18.025 INFO 16260 --- [nio-8011-exec-5] cn.qz.cloud.config.FeignLogger : [PaymentHystrixService#getSessionId] sec-fetch-dest: document 2021-01-16 23:06:18.025 INFO 16260 --- [nio-8011-exec-5] cn.qz.cloud.config.FeignLogger : [PaymentHystrixService#getSessionId] sec-fetch-mode: navigate 2021-01-16 23:06:18.026 INFO 16260 --- [nio-8011-exec-5] cn.qz.cloud.config.FeignLogger : [PaymentHystrixService#getSessionId] sec-fetch-site: none 2021-01-16 23:06:18.026 INFO 16260 --- [nio-8011-exec-5] cn.qz.cloud.config.FeignLogger : [PaymentHystrixService#getSessionId] sec-fetch-user: ?1 2021-01-16 23:06:18.027 INFO 16260 --- [nio-8011-exec-5] cn.qz.cloud.config.FeignLogger : [PaymentHystrixService#getSessionId] ---> END HTTP (0-byte body) 2021-01-16 23:06:18.028 INFO 16260 --- [nio-8011-exec-5] cn.qz.cloud.config.FeignLogger : [PaymentHystrixService#getSessionId] GET http://CLOUD-PROVIDER-HYSTRIX-PAYMENT/hystrix/payment/getSessionId HTTP/1.1, log request end. <--- 2021-01-16 23:06:18.089 INFO 16260 --- [nio-8011-exec-5] cn.qz.cloud.config.FeignLogger : [PaymentHystrixService#getSessionId] 200 HTTP/1.1 (59ms) log logAndRebufferResponse begin. <--- 2021-01-16 23:06:18.091 INFO 16260 --- [nio-8011-exec-5] cn.qz.cloud.config.FeignLogger : [PaymentHystrixService#getSessionId] <--- HTTP/1.1 200 (59ms) 2021-01-16 23:06:18.091 INFO 16260 --- [nio-8011-exec-5] cn.qz.cloud.config.FeignLogger : [PaymentHystrixService#getSessionId] connection: keep-alive 2021-01-16 23:06:18.092 INFO 16260 --- [nio-8011-exec-5] cn.qz.cloud.config.FeignLogger : [PaymentHystrixService#getSessionId] content-type: application/json 2021-01-16 23:06:18.092 INFO 16260 --- [nio-8011-exec-5] cn.qz.cloud.config.FeignLogger : [PaymentHystrixService#getSessionId] date: Sat, 16 Jan 2021 15:06:18 GMT 2021-01-16 23:06:18.093 INFO 16260 --- [nio-8011-exec-5] cn.qz.cloud.config.FeignLogger : [PaymentHystrixService#getSessionId] keep-alive: timeout=60 2021-01-16 23:06:18.094 INFO 16260 --- [nio-8011-exec-5] cn.qz.cloud.config.FeignLogger : [PaymentHystrixService#getSessionId] transfer-encoding: chunked 2021-01-16 23:06:18.094 INFO 16260 --- [nio-8011-exec-5] cn.qz.cloud.config.FeignLogger : [PaymentHystrixService#getSessionId] 2021-01-16 23:06:18.096 INFO 16260 --- [nio-8011-exec-5] cn.qz.cloud.config.FeignLogger : [PaymentHystrixService#getSessionId] {"success":true,"code":"200","msg":"","data":{"paymentCurrentUser":"张三","payment":"53972a2b-9324-4078-8446-268e13071f06"}} 2021-01-16 23:06:18.097 INFO 16260 --- [nio-8011-exec-5] cn.qz.cloud.config.FeignLogger : [PaymentHystrixService#getSessionId] <--- END HTTP (126-byte body) 2021-01-16 23:06:18.098 INFO 16260 --- [nio-8011-exec-5] cn.qz.cloud.config.FeignLogger : [PaymentHystrixService#getSessionId] 200 HTTP/1.1 (59ms) log logAndRebufferResponse end. <---
(2) payment 被调用者服务日志如下:
53972a2b-9324-4078-8446-268e13071f06 ====S cookie Idea-599589ea 7e4185c4-b2de-45e1-9f54-6ae34bfbe678 Webstorm-e34e7d83 831b2048-d1c1-45e6-b4e2-77d667e3f1c4 Hm_lvt_b393d153aeb26b46e9431fabaf0f6190 1605535026 SESSION NTM5NzJhMmItOTMyNC00MDc4LTg0NDYtMjY4ZTEzMDcxZjA2 ====E cookie ====S header accept-encoding gzip, deflate, br cloud_caller order80 cookie Idea-599589ea=7e4185c4-b2de-45e1-9f54-6ae34bfbe678; Webstorm-e34e7d83=831b2048-d1c1-45e6-b4e2-77d667e3f1c4; Hm_lvt_b393d153aeb26b46e9431fabaf0f6190=1605535026; SESSION=NTM5NzJhMmItOTMyNC00MDc4LTg0NDYtMjY4ZTEzMDcxZjA2 accept */* user-agent Java/1.8.0_121 host root:8081 connection keep-alive ====E header
至此实现了Cloud分布式项目Feign调用共享session,其实就是传递header,同时服务调用者与被调用者服务共享header中的session标识。基于Token共享方式也是这样的思路。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
2018-01-16 Java jsp页面中jstl标签详解