需求描述
使用 Spring Cloud Alibaba 搭建微服务,业务实例默认使用内网 IP 注册到 Nacos 服务端,这样在跨局域网时会无法请求成功。那如何解决呢?
答:指定外网 IP 注册到 Nacos 上。
下述方法来自网络,版权归原著作人,本人只是搬运工+实践者!
No.1 指定IP注册
在 Nacos 客户端指定IP,启动成功后即可以在 Nacos 服务端上看到对应的IP。
在 bootstrap.yml 配置文件中写入:
spring.cloud.nacos.discovery.ip = xx
spring.cloud.nacos.discovery.port = xxx
或指定网卡注册:
spring.cloud.nacos.discovery.networkInterface = xx
也可以使用spring cloud 的 InetUtils工具,配置项为,具体说明可以自行检索
spring.cloud.inetutils.default-hostname
spring.cloud.inetutils.default-ip-address
spring.cloud.inetutils.ignored-interfaces
spring.cloud.inetutils.preferred-networks
spring.cloud.inetutils.timeout-seconds
spring.cloud.inetutils.use-only-site-local-interfaces
No.2 动态注册IP-配置文件形式
packagecom.zhongyi.doctor.config;importcn.hutool.http.Header;importcn.hutool.http.HttpRequest;importcom.alibaba.cloud.nacos.NacosDiscoveryProperties;importcom.alibaba.cloud.nacos.NacosServiceManager;importcom.alibaba.cloud.nacos.discovery.NacosServiceDiscovery;importlombok.extern.slf4j.Slf4j;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.http.ResponseEntity;importorg.springframework.web.client.RestTemplate;/**
* @author SymbolWong
* @description
* @date 2023/2/6 16:25
*/@Configuration@Slf4jpublicclassNacosDiscoveryConfig{/**
* nacosConfigServerAaddr yml中配置的nacos配置中心地址
*/@Value("${spring.cloud.nacos.config.server-addr}")String nacosConfigServerAaddr;/**
* nacosConfignamespace yml中配置的nacos配置中心命名空间
*/@Value("${spring.cloud.nacos.config.namespace}")String nacosConfignamespace;/**
* getServerInternetIP 通过Nginx获取本机外网IP,需要Nginx配合配置
* @author IPMan
* @date 2022/7/10
*
* @return java.lang.String 返回本机外网IP
*/privateStringgetServerInternetIPByNginx(){//通过配置中心地址构造查询IP请求地址String url="http://"+nacosConfigServerAaddr.split(":")[0]+"/getIp";//调试输出,这里不推荐err的方式输出,这样仅为测试使用,推荐采用日志实现或者不输出// System.err.println(url);
log.warn("Nacos server addr is {}",url);//外网IPString internetIP="127.0.0.1";//这里一步完成了,构造一个RestTemplate对象,通过对指定URL执行GET请求来获取响应实体ResponseEntity<String> response =newRestTemplate().getForEntity(url,String.class);// //从响应实体对象中获取内容
internetIP = response.getBody();// //调试输出,这里不推荐err的方式输出,这样仅为测试使用,推荐采用日志实现或者不输出// System.err.println(internetIP);
log.warn("Internet ip is {}",url);return internetIP;}/**
* nacosProperties Nacos 服务发现配置类,代替yml中spring.cloud.nacos.discovery:配置
* @author IPMan
* @date 2022/7/10
*
* @return com.alibaba.cloud.nacos.NacosDiscoveryProperties
*/@BeanpublicNacosDiscoveryPropertiesnacosProperties(){//new一个nacos服务发现配置对象NacosDiscoveryProperties properties =newNacosDiscoveryProperties();//设置发现注册的IP,即注册中心详情中的IP,这里很关键,默认是Inet4Address.getLocalHost(),即如果包含子网,则获取的是子网IP
properties.setIp(getServerInternetIP());//设置注册中心地址
properties.setServerAddr(nacosConfigServerAaddr);//设置注册中心命名空间
properties.setNamespace(nacosConfignamespace);return properties;}privateStringgetServerInternetIP(){String internetip ="";String url ="https://ip.3322.org";
internetip =HttpRequest.get(url).header(Header.USER_AGENT,"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36").execute().body();
log.warn("Internet ip is {}",internetip);return internetip;}/**
* nacosServiceDiscovery nacos 服务发现对象,这个对象构造完成后是无法设置配置的
* @author IPMan
* @date 2022/7/10
*
* @param discoveryProperties com.alibaba.cloud.nacos.NacosDiscoveryProperties
* @param nacosServiceManager com.alibaba.cloud.nacos.NacosServiceManager
* @return com.alibaba.cloud.nacos.discovery.NacosServiceDiscovery
*/@BeanpublicNacosServiceDiscoverynacosServiceDiscovery(NacosDiscoveryProperties discoveryProperties,NacosServiceManager nacosServiceManager){returnnewNacosServiceDiscovery(discoveryProperties, nacosServiceManager);}}
PS:本人使用该方法虽然能注册成功,但是请求是失败的,报错:Illegal character in authority at index 7,本来以为是得到的公网IP前后有空格之类的,用了trim方法依然还是报错,有待继续研究。
No.3 动态IP注册-监听器形式
- 新建监听器类
packagecom.zhongyi.doctor.config;importcn.hutool.http.Header;importcn.hutool.http.HttpRequest;importorg.springframework.boot.context.config.ConfigFileApplicationListener;importorg.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;importorg.springframework.boot.context.event.ApplicationPreparedEvent;importorg.springframework.context.ApplicationEvent;importorg.springframework.context.event.SmartApplicationListener;importorg.springframework.core.Ordered;/**
* @author SymbolWong
* @description
* @date 2023/2/18 9:13
*/publicclassAfterConfigListenerimplementsSmartApplicationListener,Ordered{@OverridepublicbooleansupportsEventType(Class<?extendsApplicationEvent> aClass){return(ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(aClass)||ApplicationPreparedEvent.class.isAssignableFrom(aClass));}@OverridepublicintgetOrder(){return(ConfigFileApplicationListener.DEFAULT_ORDER+1);}@OverridepublicvoidonApplicationEvent(ApplicationEvent applicationEvent){String currentIp =getServerInternetIP();if(applicationEvent instanceofApplicationEnvironmentPreparedEvent){System.setProperty("spring.cloud.nacos.discovery.ip", currentIp);}}privateStringgetServerInternetIP(){String internetip ="";String url ="https://ip.3322.org";
internetip =HttpRequest.get(url).header(Header.USER_AGENT,"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36").execute().body();return internetip.trim();}}
- 启动入口处注入该监听类
SpringApplication springApplication =newSpringApplication(DoctorApplication.class);
springApplication.addListeners(newAfterConfigListener());
springApplication.run(args);
PS:使用此方法完美解决,可以愉快的跨服务器请求了!
特别强调
- 跨服务器组装业务一定要使用公网IP,千万不要用内网IP!!!
- 注意防火墙、安全组的限制!!!
参考文章
版权归原作者 SymbolWoo 所有, 如有侵权,请联系我们删除。