内容简介:这几天在用我发现在
这几天在用 spring-boot 2
的 webflux
重构一个工程,写到了一个需要获得客户端请求 IP 的地方,发现写不下去了,在如下的 Handler(webflux 中 Handler 相当于 mvc 中的 Controller)中
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Mono; import static org.springframework.web.reactive.function.server.RequestPredicates.GET; import static org.springframework.web.reactive.function.server.RequestPredicates.accept; import static org.springframework.web.reactive.function.server.RouterFunctions.route; /** * 某业务 Handler */ @Component public class SplashHandler { private Mono<ServerResponse> execute(ServerRequest serverRequest) { ... 业务代码 // serverRequest 获得 IP ? ... 业务代码 } @Configuration public static class RoutingConfiguration { @Bean public RouterFunction<ServerResponse> execute(SplashHandler handler) { return route( GET("/api/ad").and(accept(MediaType.TEXT_HTML)), handler::execute ); } } }
我发现 org.springframework.web.reactive.function.server.ServerRequest
根本没有暴露用于获得客户端 IP 的 API,想想这在传统 MVC 中是相当基本的需求啊,竟然获取不到,然后 Google 了一下,发现这个是 spring-webflux
的一个 BUG
,这个 BUG 在 spring-webflux
5.1 中解决了,但是,略有些尴尬的是当前最新稳定版的 spring-boot
还是依赖 5.0.x 的 spring-webflux
的。难道要等官方升级么,那不知道得等到什么时候,因此我接着搜了搜资料,看了看文档和源码,自己想了个曲线救国的办法。
正文
在 spring-webflux
中,有一个 org.springframework.web.server.WebFilter
接口,类似于 Servlet
API 中的过滤器,这个 API 提供了一个方法会将一个限定名为 org.springframework.web.server.ServerWebExchange
的类暴露出来,而在这个类中就包含了对于请求端 IP 的获取方法:
org.springframework.web.server.ServerWebExchange#getRequest org.springframework.http.server.reactive.ServerHttpRequest#getRemoteAddress
因此,我们大可以实现一个 WebFilter 在里面通过暴露的 ServerWebExchange
拿到客户端 IP,然后再将其塞到请求的 header 中,这样,后续过程就可以从 header 中取 IP 了。思路有了,我们开始实现吧。
过滤、取 IP、放 header,一气呵成:
import org.springframework.context.annotation.Configuration; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.stereotype.Component; import org.springframework.web.reactive.config.CorsRegistry; import org.springframework.web.reactive.config.WebFluxConfigurer; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; import reactor.core.publisher.Mono; import java.net.InetSocketAddress; import java.util.Objects; /* If you want to keep Spring Boot WebFlux features and you want to add additional WebFlux configuration, you can add your own @Configuration class of type WebFluxConfigurer but without @EnableWebFlux. If you want to take complete control of Spring WebFlux, you can add your own @Configuration annotated with @EnableWebFlux. */ @Configuration public class WebConfiguration implements WebFluxConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry .addMapping("/**") .allowedOrigins("*") .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTION") .allowedHeaders("header1", "header2", "header3") .exposedHeaders("header1", "header2") .allowCredentials(true) .maxAge(3600); } /** * https://stackoverflow.com/questions/51192630/how-do-you-get-clients-ip-address-spring-webflux-websocket?rq=1 * https://stackoverflow.com/questions/50981136/how-to-get-client-ip-in-webflux * https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-filters * 由于在低版本的 spring-webflux 中不支持直接获得请求 IP(https://jira.spring.io/browse/SPR-16681),因此写了一个补丁曲线救国, * 从 org.springframework.web.server.ServerWebExchange 中获得 IP 后,在放到 header 里 */ @Component public static class RetrieveClientIpWebFilter implements WebFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { InetSocketAddress remoteAddress = exchange.getRequest().getRemoteAddress(); String clientIp = Objects.requireNonNull(remoteAddress).getAddress().getHostAddress(); ServerHttpRequest mutatedServerHttpRequest = exchange.getRequest().mutate().header("X-CLIENT-IP", clientIp).build(); ServerWebExchange mutatedServerWebExchange = exchange.mutate().request(mutatedServerHttpRequest).build(); return chain.filter(mutatedServerWebExchange); } } }
后续过程 header 取值:
private Mono<ServerResponse> execute(ServerRequest serverRequest) { String clientIp = serverRequest.headers().asHttpHeaders().getFirst("X-CLIENT-IP") ... 业务代码 }
通过上述解决方案(其实严格上说是 hacking)就解决了我们遇到的问题了。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 曲线救国:webpack打包优化黑科技
- iOS 沿曲线线性渐变的贝塞尔曲线
- 利用Python中的numpy包实现PR曲线和ROC曲线的计算
- 有趣的椭圆曲线加密
- Flutter 实现平滑曲线折线图
- 极坐标系下的曲线
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
CSS3专业网页开发指南
Peter Gasston / 李景媛、吴晓嘉 / 人民邮电出版社 / 2014-3-1 / 45.00元
《CSS3专业网页开发指南》是英国著名Web前端开发工程师Peter Gasston对CSS3高级技术的全面介绍。书中既有CSS3的发展历史、基本语法等入门知识介绍,也涵盖了媒体查询、选择器、伪类与伪元素、网页字体、文本排版、图形处理、动画、布局等CSS3前端开发必不可少的知识,还介绍了CSS3的未来发展方向。全书共分为17章,作者在每一章的讲解中都结合了大量的实例,同时也不忘介绍每一项技术的发展......一起来看看 《CSS3专业网页开发指南》 这本书的介绍吧!