RequestContextHolder 很方便的获取 request
在 Spring boot web 中我们可以通过 RequestContextHolder 很方便的获取 request。
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
// 获取 request
HttpServletRequest request = requestAttributes.getRequest();
不再需要通过参数传递 request。在 Spring webflux 中并没提供该功能,使得我们在 Aop 或者一些其他的场景中获取 request 变成了一个奢望???
寻求解决方案
首先我想到的是看看 spring-security 中是否有对于的解决方案,因为在 spring-security 中我们也是可以通过 SecurityContextHolder 很方便快捷的获取当前登录的用户信息。
找到了 ReactorContextWebFilter,我们来看看 security 中他是怎么实现的。 https://github.com/spring-projects/spring-security/blob/master/web/src/main/java/org/springframework/security/web/server/context/ReactorContextWebFilter.java#L43
public class ReactorContextWebFilter implements WebFilter {
private final ServerSecurityContextRepository repository;
public ReactorContextWebFilter(ServerSecurityContextRepository repository) {
Assert.notNull(repository, "repository cannot be null");
this.repository = repository;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
return chain.filter(exchange)
.subscriberContext(c -> c.hasKey(SecurityContext.class) ? c :
withSecurityContext(c, exchange)
);
}
private Context withSecurityContext(Context mainContext, ServerWebExchange exchange) {
return mainContext.putAll(this.repository.load(exchange)
.as(ReactiveSecurityContextHolder::withSecurityContext));
}
}
源码里面我们可以看到 他利用一个 Filter,chain.filter(exchange) 的返回值 Mono 调用了 subscriberContext 方法。 那么我们就去了解一下这个 reactor.util.context.Context。找到 reactor 官方文档中的 名宇娱乐context 章节:https://projectreactor.io/docs/core/release/reference/#context
大意是:从 Reactor 3.1.0 开始提供了一个高级功能,可以与 ThreadLocal 媲美,应用于 Flux 和 Mono 的上下文工具 Context。更多请大家查阅官方文档,对英文比较抵触的朋友可以使用 google 翻译。
mica 中的实现
mica 中的实现比较简单,首先是我们的 ReactiveRequestContextFilter:
/**
* ReactiveRequestContextFilter
*
* @author L.cm
*/
@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public class ReactiveRequestContextFilter implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
ServerHttpRequest request = exchange.getRequest(www.gouyiflb.cn/);
return chain.filter(exchange)
.subscriberContext(ctx -> ctx.put(ReactiveRequestContextHolder.CONTEXT_KEY, request));
}
}
在 Filter 中直接将 request 存储到 Context 上下文中。
ReactiveRequestContextHolder 工具:
/**
* ReactiveRequestContextHolder
*
* @author L.cm
*/
public class ReactiveRequestContextHolder {
static final Class<ServerHttpRequest> CONTEXT_KEY = ServerHttpRequest.class;
/**
* Gets the {@code Mono<ServerHttpRequest>} from Reactor {@link Context}
* @return the {@code Mono<ServerHttpRequest>}
*/
public static Mono<ServerHttpRequest> getRequest() {
return Mono.subscriberContext()
.map(ctx -> ctx.get(CONTEXT_KEY));
}
}
怎么使用呢?
mica 中对未知异常处理,从 request 中获取请求的相关信息
@ExceptionHandler(Throwable.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Mono<?> handleError(Throwable e) {
log.error("未知异常", e);
// 发送:未知异常异常事件
return ReactiveRequestContextHolder.getRequest()
.doOnSuccess(r -> publishEvent(r, e))
.flatMap(r -> Mono.just(R.fail(SystemCode.FAILURE)));
}
private void publishEvent(ServerHttpRequest request, Throwable error) {
// 具体业务逻辑
}
WebClient 透传 request 中的 header
此示例来源于开源中国问答中笔者的回复: 《如何在gateway 中获取 webflux的 RequestContextHolder》
@GetMapping("/test")
@ResponseBody
public Mono<String> test(www.michenggw.com) {
WebClient webClient = testClient();
return webClient.get().uri("www.suoLaiervip.com").retrieve().bodyToMono(String.class);
}
@Bean
public WebClient testClient() {
return WebClient.builder()
.filter(testFilterFunction())
.baseUrl("https://www.baidu.com")
.build();
}
private ExchangeFilterFunction testFilterFunction() {
return (request, next) -> ReactiveRequestContextHolder.getRequest()
.flatMap(r -> {
ClientRequest clientRequest = ClientRequest.from(request)
.headers(headers -> headers.set(HttpHeaders.USER_AGENT, r.getHeaders().getFirst(HttpHeaders.USER_AGENT)))
.build();
return next.exchange(clientRequest);
});
}
上段代码是透传 web 中的 request 中的 user_agent 请求头到 WebClient 中。
开源推荐
RequestContextHolder 很方便的获取 request的更多相关文章
- RequestContextHolder获取request和response
RequestContextHolder获取request和response 2019年03月16日 15:18:15 whp404 阅读数:21更多 个人分类: Spring 首先需要在web. ...
- Spring MVC 中RequestContextHolder获取request和response
1.最简单方式:处理方法入参 例如: @RequestMapping("/test") @ResponseBody public void saveTest(HttpServlet ...
- springMVC中获取request和response对象的几种方式(RequestContextHolder)
springMVC中获取request和response对象的几种方式 1.最简单方式:参数 2.加入监听器,然后在代码里面获取 原文链接:https://blog.csdn.net/weixin_4 ...
- Spring中获取request的几种方法,及其线程安全性分析
前言 本文将介绍在Spring MVC开发的web系统中,获取request对象的几种方法,并讨论其线程安全性. 原创不易,如果觉得文章对你有帮助,欢迎点赞.评论.文章有疏漏之处,欢迎批评指正. 欢迎 ...
- 【转】SpringMVC,获取request的几种方法,及线程安全性
作者丨编程迷思 https://www.cnblogs.com/kismetv/p/8757260.html 概述 在使用Spring MVC开发Web系统时,经常需要在处理请求时使用request对 ...
- [No000016E]Spring 中获取 request 的几种方法,及其线程安全性分析
前言 本文将介绍在Spring MVC开发的web系统中,获取request对象的几种方法,并讨论其线程安全性. 原创不易,如果觉得文章对你有帮助,欢迎点赞.评论.文章有疏漏之处,欢迎批评指正. 欢迎 ...
- Spring中获取request的几种方法,及其线程安全性分析(山东数漫江湖)
前言 本文将介绍在Spring MVC开发的web系统中,获取request对象的几种方法,并讨论其线程安全性. 原创不易,如果觉得文章对你有帮助,欢迎点赞.评论.文章有疏漏之处,欢迎批评指正. 欢迎 ...
- Spring中如何获取request的方法汇总及其线程安全性分析
前言 本文将介绍在Spring MVC开发的web系统中,获取request对象的几种方法,并讨论其线程安全性.下面话不多说了,来一起看看详细的介绍吧. 概述 在使用Spring MVC开发Web系统 ...
- springmvc在使用@ModelAttribute注解获取Request和Response会产生线程并发不安全问题(转)
springmvc在获取Request和Response有很多方式:具体请看:https://www.cnblogs.com/wade-luffy/p/8867144.html 产生线程问题的代码如下 ...
随机推荐
- 把玩Alpine linux(二):APK包管理器
导读 Alpine Linux非常精简,开机内存占用也在二三十兆大,没有拆箱即用,就需要我们自己去做一些了解和配置 Alpine Linux的优劣 优势 Alpine Linux的Docker镜像特点 ...
- 牛客练习赛38 D 题 出题人的手环 (离散化+树状数组求逆序对+前缀和)
链接:https://ac.nowcoder.com/acm/contest/358/D来源:牛客网 出题人的手环 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 524288K,其他 ...
- DelegatingFilterProxy作用浅析
<filter> <filter-name>secondDomainFilter</filter-name> <filter-class>org.spr ...
- source map
一.source map 概述 我们在打包中,将开发环境中源代码经过压缩,去空格,babel编译转化,最终可以得到适用于生产环境的项目代码,这样处理后的项目代码和源代码之间差异性很大,会造成无法deb ...
- [转帖]buffer与cache的区别
作者:沈万马链接:https://www.zhihu.com/question/26190832/answer/146259979来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注 ...
- [转帖]web安全:通俗易懂,以实例讲述破解网站的原理及如何进行防护!如何让网站变得更安全。
web安全:通俗易懂,以实例讲述破解网站的原理及如何进行防护!如何让网站变得更安全. https://www.cnblogs.com/1996V/p/7458377.html 感谢原作者写的内容 安全 ...
- flutter图片铺满父框
正常我们需要显示一张图片,会用到Image这个控件. 打个比方,我们加载一张本地的图片, 先看一下这个Image.asset的源码: Image.asset(String name, { Key ke ...
- linux audit审计(3)--audit服务配置
audit守护进程可以通过/etc/audit/auditd.conf文件进行配置,默认的auditd配置文件可以满足大多数环境的要求. local_events = yes write_logs = ...
- HashMap、HashTable、ConcurrentHashMap、HashSet区别 线程安全类
HashMap专题:HashMap的实现原理--链表散列 HashTable专题:Hashtable数据存储结构-遍历规则,Hash类型的复杂度为啥都是O(1)-源码分析 Hash,Tree数据结构时 ...
- DELPHI中MDI子窗口的关闭和打开
DELPHI中MDI子窗口的关闭 和打开 Delphi中MDI子窗口的关闭方式默认为缩小而不是关闭,所以当你单击子窗口右上角的关闭按钮时会 发觉该子窗口只是最小化,而不是你预期的那样被 ...