赞
踩
最近接手一个项目,各子工程之间通过feign调用;各服务部署在K8S上,通过nacos管理配置;由于服务部署的机器无法开放端口等原因,导致本机服务与测试环境网络端口无法互通,故需要重写feign的调用地址;个人总结的方法有以下几种:
目录
在feignclient里写一个固定地址或者写一个可配置的地址,这样可以在配置文件里指定,这种方式在创建feign客户端的时候就需要规划好。
1.1 固定地址
- @FeignClient(name = "feignCustomerService", url = "http://localhost:8080")
- public interface FeignCustomerService {
- /**
- * 请求客户的接口
- */
- @RequestMapping(value = "order/update", method = RequestMethod.POST)
- @Headers(value = "Content-Type: application/json")
- OrderHttpResponse updateOrder(@RequestBody OrderUpdateDTO orderUpdateDTO);
-
- }
1.2 可配置的地址
- @FeignClient(name = "feignCustomerService", url = "${customer.url}")
- public interface FeignCustomerService {
-
- @RequestMapping(value = "test/list", method = RequestMethod.POST)
- @Headers(value = "Content-Type: application/json")
- OrderHttpResponse updateTest(@RequestBody OrderUpdateDTO orderUpdateDTO);
-
- }
配置文件配置地址
customer.url=http://localhost:8080
这种方式具有局限性,在nacos上注册的服务IP与本机IP不一致的时候(连接VPN)可能依旧调不通服务,但是实现RequestInterceptor接口可以处理全局请求(header,身份认证等)
- @Component
- public class Oauth2TokenRequestInterceptor implements RequestInterceptor {
-
- @Override
- public void apply(RequestTemplate requestTemplate) {
- // 获取请求中的消息头
- ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
- HttpServletRequest request = attributes.getRequest();
- String requestHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
- if (StringUtils.isNotBlank(requestHeader) && requestHeader.startsWith("Bearer ")) {
- // 将消息头塞入到请求模板中
- requestTemplate.header(HttpHeaders.AUTHORIZATION, requestHeader);
- }
- //重写URL,访问指定服务
- String url = target.url();
- String newUrl = "http://localhost:8080";
- template.target(newUrl );
- }
- }
这种方式可以自定义负载均衡的策略,也可以自定义访问指定服务IP,这里以FeignBlockingLoadBalancerClient为例
配置类
- package com.***.redirect;
-
- import lombok.Getter;
- import lombok.Setter;
- import org.springframework.boot.context.properties.ConfigurationProperties;
- import org.springframework.cloud.context.config.annotation.RefreshScope;
- import org.springframework.stereotype.Component;
-
- import java.util.Map;
-
- @Getter
- @Setter
- @RefreshScope
- @ConfigurationProperties("localbalance")
- @Component
- public class LocalFeignPerpreties {
- private Boolean enable;
- private Map<String,String> rule;
- }
配置文件配置内容:
- localbalance:
- enable: true
- rule:
- aiflow-sys: http://IP:8888/SERVICE
- aiflow-auth: http://IP:8888/SERVICE
重写FeignBlockingLoadBalancerClient 的execute方法
- package com.***.redirect;
-
- import feign.Client;
- import feign.Request;
- import feign.RequestTemplate;
- import feign.Response;
- import lombok.extern.slf4j.Slf4j;
- import org.apache.commons.lang3.StringUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
- import org.springframework.cloud.client.ServiceInstance;
- import org.springframework.cloud.client.discovery.DiscoveryClient;
- import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
- import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
- import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient;
- import org.springframework.cloud.openfeign.ribbon.CachingSpringLoadBalancerFactory;
- import org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient;
- import org.springframework.context.annotation.Primary;
- import org.springframework.util.Assert;
- import org.springframework.web.context.request.RequestContextHolder;
- import org.springframework.web.context.request.ServletRequestAttributes;
- import org.springframework.web.util.UriComponentsBuilder;
-
- import javax.servlet.http.HttpServletRequest;
- import java.io.IOException;
- import java.net.URI;
- import java.net.URLEncoder;
- import java.nio.charset.Charset;
- import java.util.*;
-
- //@ConditionalOnBean
- //@Primary
- @Slf4j
- public class LocalBlockingLoadBalancerClient extends FeignBlockingLoadBalancerClient {
- private Client delegate;
- private BlockingLoadBalancerClient loadBalancerClient;
- @Autowired
- private LocalFeignPerpreties localFeignPerpreties;
-
- public LocalBlockingLoadBalancerClient(Client delegate,
- BlockingLoadBalancerClient loadBalancerClient) {
- super(delegate, loadBalancerClient);
- this.delegate = delegate;
- this.loadBalancerClient = loadBalancerClient;
- }
-
- @Override
- public Response execute(Request request, Request.Options options) throws IOException {
- try {
- log.info("feign -> 配置化客户端");
- Boolean enable = localFeignPerpreties.getEnable();
- if (enable) {
- String url = request.url();
- RequestTemplate requestTemplate = request.requestTemplate();
- String name = requestTemplate.feignTarget().name();
- Map<String, String> urlMap = localFeignPerpreties.getRule();
- if (urlMap != null && urlMap.containsKey(name)) {
- URI uri = URI.create(url);
- StringBuffer strbuf = new StringBuffer();
- strbuf.append(urlMap.get(name)).append(uri.getPath());
- if (StringUtils.isNotBlank(uri.getQuery())) {
- strbuf.append("?").append(uri.getQuery());
- }
- requestTemplate.target(urlMap.get(name));
- Map<String, Collection<String>> headers = request.headers();
- Map<String, Collection<String>> newheaders = new HashMap<>();
- //处理请求头
- ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
- HttpServletRequest attributesRequest = attributes.getRequest();
- Enumeration<String> headerNames = attributesRequest.getHeaderNames();
- if (headerNames != null) {
- while (headerNames.hasMoreElements()) {
- String element = headerNames.nextElement();
- String elementVal = attributesRequest.getHeader(element);
- newheaders.put(element, new ArrayList<String>() {{
- add(elementVal);
- }});
- }
- }
- //构建新的request
- Request newRequest = buildRequest(request, strbuf.toString(), newheaders);
- return super.getDelegate().execute(newRequest, options);
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- log.info("feign -> 默认客户端");
- return super.execute(request, options);
- }
-
- protected Request buildRequest(Request request,
- String reconstructedUrl,
- Map<String, Collection<String>> headers) {
- return Request.create(request.httpMethod(), reconstructedUrl, headers,
- request.body(), Charset.forName("UTF-8"), request.requestTemplate());
- }
-
- }
使配置类和重写的client生效
- package com.***.redirect;
-
- import feign.Client;
- import org.springframework.boot.context.properties.EnableConfigurationProperties;
- import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
-
- //@ConditionalOnProperty(prefix = ReBalancerProperties.prefix,name = "enable",havingValue = "true")
- @Configuration
- @EnableConfigurationProperties(value = {LocalFeignPerpreties.class})
- public class ReBalancerConfiguration {
-
- @Bean
- public Client feignReBalancer(BlockingLoadBalancerClient discoveryClient) {
-
- return new LocalBlockingLoadBalancerClient(new Client.Default(null, null),
- discoveryClient);
- }
- }
到这里基本上可以满足重写feign URL的需求了,这个前提条件是代码在application启动类的下一级,如果不在启动类的同级或者下一级,是无法扫描到相关类的,这时我们可以注解完成扫描,需要在启动类上加上相关注解
- package com.***.annotation;
-
- import com.***.ReBalancerConfiguration;
- import org.springframework.boot.autoconfigure.AutoConfigurationPackage;
- import org.springframework.context.annotation.Import;
-
- import java.lang.annotation.ElementType;
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
- import java.lang.annotation.Target;
-
- @Target({ElementType.TYPE})
- @Retention(RetentionPolicy.RUNTIME)
- @Import(ReBalancerConfiguration.class)
- @AutoConfigurationPackage
- public @interface EnableLocalFeignClient {
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。