我最新最全的文章都在 南瓜慢说 www.pkslow.com,欢送大家来喝茶!
1 不一样的世界
在惯例的 Spring Web
我的项目中,咱们要获取 Request
对象是十分不便的,不少库都提供了静态方法来获取。获取代码如下:
ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
// get the request
HttpServletRequest request = requestAttributes.getRequest();
在类 RequestContextHolder
提供了静态方法,也就意味着你能够在任何中央调用。而它应用了 ThreadLocal
来保留 Request
对象,也就是不同线程是能够获取各自的 Request 对象。
但在响应式 WebFlux
的世界里,并没有提供相似的 Holder
类,而 WebFlux
是无奈感知线程的,任何一个线程能够在任何时候解决任何申请,如果它感觉切换以后线程更有效率,它就会这么做。但在 Servlet Based
的利用里,它会为某个申请安顿一个线程去解决残缺个过程。
这个微小的差异,意味着不能简略地通过 ThreadLocal
来保留和获取 Request
了。
2 先保留,再获取
为了在前面能够不便取得 Request
对象,咱们就须要在开始的时候把它存在一个能够应用、并且是雷同 scope
的容器里。这里须要解决两个关键问题:
(1)Request
对象从何而来;
(2)存在哪里?
针对问题(1),咱们能够回忆什么时候会呈现 Request
对象,最容易想得到的就是 WebFilter
了,它的办法签名如下:
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain);
咱们能够通过 ServerWebExchange
间接获取到 Request
对象:
ServerHttpRequest request = exchange.getRequest();
而因为 Filter
是能够先于应用逻辑执行的,所以满足要求,问题(1)解决。
针对问题(2),须要一个与 Reavtive
申请雷同范畴的容器,reactor.util.context.Context
能够满足需要。查看 reactor
的官网文档(https://projectreactor.io/doc…)可见上面这段话:
Since version
3.1.0
, Reactor comes with an advanced feature that is somewhat comparable toThreadLocal
but can be applied to aFlux
or aMono
instead of aThread
. This feature is calledContext
.
并且官网也给出了为何 ThreadLocal
在某些场景不实用的解释,有趣味能够看看。
3 代码实现
3.1 WebFilter 获取并保留
首先,在 WebFilter
中获取 Request
对象并保留,代码如下:
@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public class ReactiveRequestContextFilter implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {ServerHttpRequest request = exchange.getRequest();
return chain.filter(exchange)
.subscriberContext(ctx -> ctx.put(ReactiveRequestContextHolder.CONTEXT_KEY, request));
}
}
从 ServerWebExchange
中获取到 ServerHttpRequest
对象,再通过 put
办法把它放进 Context
里。
3.2 工具类 Holder
实现一个工具类来提供静态方法,在 Filter
后的任何场景都能够应用:
public class ReactiveRequestContextHolder {
public static final Class<ServerHttpRequest> CONTEXT_KEY = ServerHttpRequest.class;
public static Mono<ServerHttpRequest> getRequest() {return Mono.subscriberContext()
.map(ctx -> ctx.get(CONTEXT_KEY));
}
}
3.3 在 Controller 中应用
咱们尝试在 Controller
中应用 ReactiveRequestContextHolder
来获取Request
:
@RestController
public class GetRequestController {@RequestMapping("/request")
public Mono<String> getRequest() {return ReactiveRequestContextHolder.getRequest()
.map(request -> request.getHeaders().getFirst("user"));
}
}
下面办法获取了 Request
对象,而后再获取了 Request
中的Header
。
启动利用,测试如下:
$ curl http://localhost:8088/request -H 'user: pkslow'
pkslow
$ curl http://localhost:8088/request -H 'user: larry'
larry
$ curl http://localhost:8088/request -H 'user: www.pkslow.com'
www.pkslow.com
能够胜利获取申请头user
。
4 总结
代码请查看:https://github.com/LarryDpk/p…
欢送关注微信公众号 <南瓜慢说>,将继续为你更新 …
多读书,多分享;多写作,多整顿。