在 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的更多相关文章

  1. RequestContextHolder获取request和response

    RequestContextHolder获取request和response 2019年03月16日 15:18:15 whp404 阅读数:21更多 个人分类: Spring   首先需要在web. ...

  2. Spring MVC 中RequestContextHolder获取request和response

    1.最简单方式:处理方法入参 例如: @RequestMapping("/test") @ResponseBody public void saveTest(HttpServlet ...

  3. springMVC中获取request和response对象的几种方式(RequestContextHolder)

    springMVC中获取request和response对象的几种方式 1.最简单方式:参数 2.加入监听器,然后在代码里面获取 原文链接:https://blog.csdn.net/weixin_4 ...

  4. Spring中获取request的几种方法,及其线程安全性分析

    前言 本文将介绍在Spring MVC开发的web系统中,获取request对象的几种方法,并讨论其线程安全性. 原创不易,如果觉得文章对你有帮助,欢迎点赞.评论.文章有疏漏之处,欢迎批评指正. 欢迎 ...

  5. 【转】SpringMVC,获取request的几种方法,及线程安全性

    作者丨编程迷思 https://www.cnblogs.com/kismetv/p/8757260.html 概述 在使用Spring MVC开发Web系统时,经常需要在处理请求时使用request对 ...

  6. [No000016E]Spring 中获取 request 的几种方法,及其线程安全性分析

    前言 本文将介绍在Spring MVC开发的web系统中,获取request对象的几种方法,并讨论其线程安全性. 原创不易,如果觉得文章对你有帮助,欢迎点赞.评论.文章有疏漏之处,欢迎批评指正. 欢迎 ...

  7. Spring中获取request的几种方法,及其线程安全性分析(山东数漫江湖)

    前言 本文将介绍在Spring MVC开发的web系统中,获取request对象的几种方法,并讨论其线程安全性. 原创不易,如果觉得文章对你有帮助,欢迎点赞.评论.文章有疏漏之处,欢迎批评指正. 欢迎 ...

  8. Spring中如何获取request的方法汇总及其线程安全性分析

    前言 本文将介绍在Spring MVC开发的web系统中,获取request对象的几种方法,并讨论其线程安全性.下面话不多说了,来一起看看详细的介绍吧. 概述 在使用Spring MVC开发Web系统 ...

  9. springmvc在使用@ModelAttribute注解获取Request和Response会产生线程并发不安全问题(转)

    springmvc在获取Request和Response有很多方式:具体请看:https://www.cnblogs.com/wade-luffy/p/8867144.html 产生线程问题的代码如下 ...

随机推荐

  1. 把玩Alpine linux(二):APK包管理器

    导读 Alpine Linux非常精简,开机内存占用也在二三十兆大,没有拆箱即用,就需要我们自己去做一些了解和配置 Alpine Linux的优劣 优势 Alpine Linux的Docker镜像特点 ...

  2. 牛客练习赛38 D 题 出题人的手环 (离散化+树状数组求逆序对+前缀和)

    链接:https://ac.nowcoder.com/acm/contest/358/D来源:牛客网 出题人的手环 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 524288K,其他 ...

  3. DelegatingFilterProxy作用浅析

    <filter> <filter-name>secondDomainFilter</filter-name> <filter-class>org.spr ...

  4. source map

    一.source map 概述 我们在打包中,将开发环境中源代码经过压缩,去空格,babel编译转化,最终可以得到适用于生产环境的项目代码,这样处理后的项目代码和源代码之间差异性很大,会造成无法deb ...

  5. [转帖]buffer与cache的区别

    作者:沈万马链接:https://www.zhihu.com/question/26190832/answer/146259979来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注 ...

  6. [转帖]web安全:通俗易懂,以实例讲述破解网站的原理及如何进行防护!如何让网站变得更安全。

    web安全:通俗易懂,以实例讲述破解网站的原理及如何进行防护!如何让网站变得更安全. https://www.cnblogs.com/1996V/p/7458377.html 感谢原作者写的内容 安全 ...

  7. flutter图片铺满父框

    正常我们需要显示一张图片,会用到Image这个控件. 打个比方,我们加载一张本地的图片, 先看一下这个Image.asset的源码: Image.asset(String name, { Key ke ...

  8. linux audit审计(3)--audit服务配置

    audit守护进程可以通过/etc/audit/auditd.conf文件进行配置,默认的auditd配置文件可以满足大多数环境的要求. local_events = yes write_logs = ...

  9. HashMap、HashTable、ConcurrentHashMap、HashSet区别 线程安全类

    HashMap专题:HashMap的实现原理--链表散列 HashTable专题:Hashtable数据存储结构-遍历规则,Hash类型的复杂度为啥都是O(1)-源码分析 Hash,Tree数据结构时 ...

  10. DELPHI中MDI子窗口的关闭和打开

    DELPHI中MDI子窗口的关闭 和打开       Delphi中MDI子窗口的关闭方式默认为缩小而不是关闭,所以当你单击子窗口右上角的关闭按钮时会   发觉该子窗口只是最小化,而不是你预期的那样被 ...