解决spring-boot2.0.6中webflux无法获得请求IP的问题

2025-05-29 0 41

这几天在用 spring-boot 2 的 webflux 重构一个工程,写到了一个需要获得客户端请求 ip 的地方,发现写不下去了,在如下的 handler(webflux 中 handler 相当于 mvc 中的 controller)中

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34
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 的获取方法:

?

1

2
org.springframework.web.server.serverwebexchange#getrequest

org.springframework.http.server.reactive.serverhttprequest#getremoteaddress

因此,我们大可以实现一个 webfilter 在里面通过暴露的 serverwebexchange 拿到客户端 ip,然后再将其塞到请求的 header 中,这样,后续过程就可以从 header 中取 ip 了。思路有了,我们开始实现吧。

过滤、取 ip、放 header,一气呵成:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47
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 取值:

?

1

2

3

4
private mono<serverresponse> execute(serverrequest serverrequest) {

string clientip = serverrequest.headers().ashttpheaders().getfirst("x-client-ip")

... 业务代码

}

通过上述解决方案(其实严格上说是 hacking)就解决了我们遇到的问题了。

总结

以上所述是小编给大家介绍的解决spring-boot2.0.6中webflux无法获得请求ip的问题,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对快网idc网站的支持!

原文链接:https://since1986.github.io/blog/5f5b006f.html

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 解决spring-boot2.0.6中webflux无法获得请求IP的问题 https://www.kuaiidc.com/111032.html

相关文章

发表评论
暂无评论