“This is the 15th day of my participation in the More Text Challenge. For more details, see more Text Challenge.”

Introduction to Spring Cloud OpenFeign Basics

OpenFeign of actual combat

Replace the default Client

By default, Feign uses the JDK’s native URLConnection to send HTTP requests. There is no connection pool, but it maintains one persistent connection per address, using HTTP’s persistence connection. This can be replaced with a good Client. This allows you to set connection pools, timeouts, and so on to tune calls between services. Here’s how to replace Feign’s default Client with Http Client and Okhttp. The steps are simple.

Use Http Client to replace the default Client

pom.xml

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <! -- Dependencies on Spring Cloud OpenFeign Starter -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <! -- Use Apache HttpClient instead of Feign native HttpClient -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
        </dependency>
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
        </dependency>
    </dependencies>
Copy the code

application.yml

server:
  port: 8010
spring:
  application:
    name: openfeign-httpclient
feign:
  httpclient:
    enabled: true
Copy the code

Some of the Http Client configuration can also be configured in the configuration file

In the org. Springframework. Cloud. Openfeign. Clientconfig. Is about HttpClient HttpClientFeignConfiguration configuration:

@Configuration( proxyBeanMethods = false )
@ConditionalOnMissingBean({CloseableHttpClient.class})
public class HttpClientFeignConfiguration {
    private final Timer connectionManagerTimer = new Timer("FeignApacheHttpClientConfiguration.connectionManagerTimer".true);
    private CloseableHttpClient httpClient;
    @Autowired( required = false )
    private RegistryBuilder registryBuilder;

    public HttpClientFeignConfiguration(a) {}@Bean
    @ConditionalOnMissingBean({HttpClientConnectionManager.class})
    public HttpClientConnectionManager connectionManager(ApacheHttpClientConnectionManagerFactory connectionManagerFactory, FeignHttpClientProperties httpClientProperties) {
        final HttpClientConnectionManager connectionManager = connectionManagerFactory.newConnectionManager(httpClientProperties.isDisableSslValidation(), httpClientProperties.getMaxConnections(), httpClientProperties.getMaxConnectionsPerRoute(), httpClientProperties.getTimeToLive(), httpClientProperties.getTimeToLiveUnit(), this.registryBuilder);
        this.connectionManagerTimer.schedule(new TimerTask() {
            public void run(a) { connectionManager.closeExpiredConnections(); }},30000L, (long)httpClientProperties.getConnectionTimerRepeat());
        return connectionManager;
    }

    @Bean
    @ConditionalOnProperty( value = {"feign.compression.response.enabled"}, havingValue = "true" )
    public CloseableHttpClient customHttpClient(HttpClientConnectionManager httpClientConnectionManager, FeignHttpClientProperties httpClientProperties) {
        HttpClientBuilder builder = HttpClientBuilder.create().disableCookieManagement().useSystemProperties();
        this.httpClient = this.createClient(builder, httpClientConnectionManager, httpClientProperties);
        return this.httpClient;
    }

    @Bean
    @ConditionalOnProperty( value = {"feign.compression.response.enabled"}, havingValue = "false", matchIfMissing = true )
    public CloseableHttpClient httpClient(ApacheHttpClientFactory httpClientFactory, HttpClientConnectionManager httpClientConnectionManager, FeignHttpClientProperties httpClientProperties) {
        this.httpClient = this.createClient(httpClientFactory.createBuilder(), httpClientConnectionManager, httpClientProperties);
        return this.httpClient;
    }

    private CloseableHttpClient createClient(HttpClientBuilder builder, HttpClientConnectionManager httpClientConnectionManager, FeignHttpClientProperties httpClientProperties) { RequestConfig defaultRequestConfig = RequestConfig.custom().setConnectTimeout(httpClientProperties.getConnectionTimeout()).setRedirectsEnabled(httpClientProp erties.isFollowRedirects()).build(); CloseableHttpClient httpClient = builder.setDefaultRequestConfig(defaultRequestConfig).setConnectionManager(httpClientConnectionManager).build();return httpClient;
    }

    @PreDestroy
    public void destroy(a) throws Exception {
        this.connectionManagerTimer.cancel();
        if (this.httpClient ! =null) {
            this.httpClient.close(); }}}Copy the code

Obviously this class will generate the default configuration for the HttpClient when there is no CloseableHttpClient bean. So custom configuration for HttpClient can be done by injecting CloseableHttpClient yourself. And the bean HttpClientConnectionManager connection management. OpenFeign actually supports HttpClient well because some of its properties can be configured in a configuration file.

Replace the default Client with Okhttp

The same configuration as the Http Client is enabled in the configuration file

pom.xml

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <! -- Dependencies on Spring Cloud OpenFeign Starter -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-okhttp</artifactId>
        </dependency>
    </dependencies>
Copy the code

application.yml

server:
  port: 8011
spring:
  application:
    name: openfeign-okhttp
feign:
  okhttp:
    enabled: true
# log
logging:
  level:
    com.msr.better.feign.service.HelloFeignService: debug
Copy the code

When this is enabled, the Client is replaced. Similarly in the org. Springframework. Cloud. Openfeign. Clientconfig package, also have a about Okhttp configuration class.

@Configuration( proxyBeanMethods = false )
@ConditionalOnMissingBean({OkHttpClient.class})
public class OkHttpFeignConfiguration {
    private OkHttpClient okHttpClient;

    public OkHttpFeignConfiguration(a) {}@Bean
    @ConditionalOnMissingBean({ConnectionPool.class})
    public ConnectionPool httpClientConnectionPool(FeignHttpClientProperties httpClientProperties, OkHttpClientConnectionPoolFactory connectionPoolFactory) {
        Integer maxTotalConnections = httpClientProperties.getMaxConnections();
        Long timeToLive = httpClientProperties.getTimeToLive();
        TimeUnit ttlUnit = httpClientProperties.getTimeToLiveUnit();
        return connectionPoolFactory.create(maxTotalConnections, timeToLive, ttlUnit);
    }

    @Bean
    public OkHttpClient client(OkHttpClientFactory httpClientFactory, ConnectionPool connectionPool, FeignHttpClientProperties httpClientProperties) {
        Boolean followRedirects = httpClientProperties.isFollowRedirects();
        Integer connectTimeout = httpClientProperties.getConnectionTimeout();
        this.okHttpClient = httpClientFactory.createBuilder(httpClientProperties.isDisableSslValidation()).connectTimeout((long)connectTimeout, TimeUnit.MILLISECONDS).followRedirects(followRedirects).connectionPool(connectionPool).build();
        return this.okHttpClient;
    }

    @PreDestroy
    public void destroy(a) {
        if (this.okHttpClient ! =null) {
            this.okHttpClient.dispatcher().executorService().shutdown();
            this.okHttpClient.connectionPool().evictAll(); }}}Copy the code

Obviously OkHttpClient is the class that performs the core functionality. Because there is a class of OpenFeign FeignHttpClientProperties, with this kind of HttpClient properties can be set up in the configuration file. Okhttp does not have a similar class, so you can generally inject your own OkHttpClient to set these properties

@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class OkHttpConfig {

    @Bean
    public okhttp3.OkHttpClient okHttpClient(a) {
        return new okhttp3.OkHttpClient.Builder()
                // Set connection timeout
                .connectTimeout(60, TimeUnit.SECONDS)
                // Set the read timeout
                .readTimeout(60, TimeUnit.SECONDS)
                // Set write timeout
                .writeTimeout(60, TimeUnit.SECONDS)
                // Whether to automatically reconnect
                .retryOnConnectionFailure(true)
                .connectionPool(new ConnectionPool())
                // Build the OkHttpClient object.build(); }}Copy the code

For a custom OkHttpClient configuration, see OpenFeign’s OkHttpFeignConfiguration, such as the ConnectionPool bean.

Multi-parameter passing for Post and Get

When using OpenFeign to implement calls between services, many times multiple parameters are passed.

Create the cloud-OpenFeign-Eureka-server module

Eureka Server registry

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <! -- springboot web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                    <groupId>org.springframework.boot</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <! Use undertow instead of Tomcat -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-undertow</artifactId>
        </dependency>
        <dependency>
            <groupId>io.undertow</groupId>
            <artifactId>undertow-servlet</artifactId>
        </dependency>
    </dependencies>
Copy the code

Configuration file application.yml

server:
  port: 8761
eureka:
  instance:
    hostname: localhost
  server :
    enable-self-preservation: false
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
Copy the code

Start the class

@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
    public static void main(String[] args) { SpringApplication.run(EurekaApplication.class, args); }}Copy the code

Create cloud-OpenFeign-Provider module

Service provider

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    </dependencies>
Copy the code

Configuration file application.yml

server:
  port: 8012
spring:
  application:
    name: openfeign-provider
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
  #eureka.instance.prefer-ip-address indicates that the IP address is registered with the Eureka Server.
  If not configured, the host name of the current service provider will be registered with the Eureka Server.
  instance:
    prefer-ip-address: true
Copy the code

Entity classes and controllers

public class Order {
    private Long id;
    private String name;
    private int age;

    public Long getId(a) {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName(a) {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge(a) {
        return age;
    }

    public void setAge(int age) {
        this.age = age; }}Copy the code
@RestController
@RequestMapping("/order")
public class OrderController {

    @GetMapping(value = "/add")
    public String addUser(Order order, HttpServletRequest request) {
        String token = request.getHeader("oauthToken");
        return "hello," + order.getName();
    }

    @PostMapping(value = "/update")
    public String updateUser(@RequestBody Order order) {
        return "hello,"+ order.getName(); }}Copy the code

Start the class

@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApplication {
    public static void main(String[] args) { SpringApplication.run(ProviderApplication.class, args); }}Copy the code

Create the cloud-OpenFeign-Consumer module

Consumer services

<dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <! -- Use Apache HttpClient instead of Feign native HttpClient -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
        </dependency>
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
        </dependency>
    </dependencies>
Copy the code

Configuration file application.yml

server:
  port: 8011
spring:
  application:
    name: openfeign-consumer
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka
feign:
  httpclient:
    enabled: true
Copy the code

Entity class

package com.msr.better.feign.model;

public class Order {
    private Long id;
    private String name;
    private int nums;
	// The getter and setter are omitted
}
Copy the code

FeignClient interface

@FeignClient("openfeign-provider")
public interface OrderApiService {
    @GetMapping(value = "/order/add")
    String addUser(@SpringQueryMap Order order);

    @PostMapping(value = "/order/update")
    String updateUser(@RequestBody Order order);
}
Copy the code

The Client interface here uses the annotation @SpringQueryMap for the GET request passing entity class. The OpenFeign@QueryMap annotation supports poJOs as GET parameter mappings. But the default OpenFeign QueryMap annotation is incompatible with Spring because it lacks the value attribute.

Spring Cloud OpenFeign provides the equivalent @SpringQueryMap annotation for annotating POJO or Map parameters as query parameter mappings.

In some sources, it is said that OpenFeign’s GET can’t pass POJOs. I wrote an interceptor to convert entity classes. I think OpenFeign has a lower version, and the new OpenFeign has support for QueryMap.

The configuration class

@Configuration
public class CoreAutoConfiguration {

    @Autowired
    private HttpClient httpClient;

    @Bean
    public HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory(a) {
        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
        factory.setHttpClient(httpClient);
        factory.setReadTimeout(3000);
        factory.setConnectTimeout(3000);
        factory.setConnectionRequestTimeout(3000);
        return factory;
    }

    / * * * {@linkThe setRequestFactory method of RestTemplate} supports HttpClient and Okhttp clients.@linkHttp request is to use native URLConnection SimpleClientHttpRequestFactory} * *@returnRestTemplate bean * /
    @LoadBalanced
    @Bean
    public RestTemplate restTemplate(a) {
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.setRequestFactory(httpComponentsClientHttpRequestFactory());
        returnrestTemplate; }}Copy the code

Above is the Client that replaced the RestTemplate. Because RestTemplate uses URLConnection by default. HttpClient is used instead.

The controller

@RestController
@RequestMapping("api")
public class OrderController {

    @Autowired
    private OrderApiService orderApiService;

    / * * *@param order
     * @return* /
    @PostMapping("/get/pojo")
    public String getPojo(@RequestBody Order order) {
        return orderApiService.addUser(order);
    }

    @PostMapping("/post/pojo")
    String postPojo(@RequestBody Order order){
        returnorderApiService.updateUser(order); }}Copy the code

Finally can test the http://localhost:8011/get/pojo and http://localhost:8011/post/pojo.

File upload

Continue using the Eureka Server created in the previous section. Then create the following two modules for file upload.

To achieve file upload function, you need to write Encoder to achieve file upload. Now OpenFeign offers a subproject called Feign – Form (github.com/OpenFeign/f…)

Create a cloud – openfeign – fileupload – server

Provider of the file upload interface

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>
Copy the code

Configuration file application.yml

server:
  port: 8012
spring:
  application:
    name: openfeign-file-server

eureka:
  server:
    enableSelfPreservation: false
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true
Copy the code

Start the class

@SpringBootApplication
@EnableDiscoveryClient
public class SCFeignFileServerApplication {
    public static void main(String[] args) { SpringApplication.run(SCFeignFileServerApplication.class, args); }}Copy the code

Upload interface

@RestController
public class FileController {

    @PostMapping(value = "/uploadFile/server", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public String fileUploadServer(MultipartFile file ) throws Exception{
        returnfile.getOriginalFilename(); }}Copy the code

Create a cloud – openfeign – fileupload – client

The caller of the file upload interface

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <! -- Dependencies on Spring Cloud OpenFeign Starter -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <! Feign file upload dependencies -->
        <dependency>
            <groupId>io.github.openfeign.form</groupId>
            <artifactId>feign-form</artifactId>
            <version>3.8.0</version>
        </dependency>

        <dependency>
            <groupId>io.github.openfeign.form</groupId>
            <artifactId>feign-form-spring</artifactId>
        </dependency>
    </dependencies>
Copy the code

Configuration file application.yml

server:
  port: 8011
spring:
  application:
    name: openfeign-upload-client
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka
Copy the code

The configuration class

@Configuration
public class FeignMultipartSupportConfig {

    @Bean
    @Primary
    @Scope("prototype")
    public Encoder multipartFormEncoder(a) {
        return newSpringFormEncoder(); }}Copy the code

The controller

@RestController
@RequestMapping("file")
public class FeignUploadController {

    @Autowired
    private FileUploadApiService fileUploadApiService;

    @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public String imageUpload(MultipartFile file) throws Exception {
        returnfileUploadApiService.fileUpload(file); }}Copy the code

FeignClient

@FeignClient(value = "openfeign-file-server", configuration = FeignMultipartSupportConfig.class)
public interface FileUploadApiService {
    /*** * 1. Produces, Consumes specifies * 2. Pay attention to distinguish between@RequestPartAnd RequestParam, don't take *@RequestPart(value = "file"@RequestParam(value = "file")
     * @param file
     * @return* /
    @PostMapping(value = "/uploadFile/server", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    String fileUpload(@RequestPart(value = "file") MultipartFile file);
}
Copy the code

test

Run the Eureka Server, cloud-OpenFeign – Fileupload-client module and cloud-OpenFeign – Fileupload-server module, using PostMan to test. Finally, the file name is successfully returned, and the file is successfully uploaded to the server.

Resolve the first request failure problem

Because OpenFeign integrates the Ribbon and Hystrix, the first call may fail.

The main reason: Hystrix’s default timeout is 1 second, and if there is no response after that, fallback code will be entered. Because of the Bean’s assembly and lazy loading mechanisms, Feign is slow on the first request. If the response time is longer than 1 second, the fallback will enter and the request will fail. Solution:

  1. It is better to increase the timeout of Hystrix

    hystrix:
      command:
        default:
       execution:
            isolation:
              thread:
                timeoutInMillseconds: 5000 # 5 seconds
    Copy the code
  2. The timeout period of Hystrix is disabled

    hystrix:
      command:
        default:
          execution:
            timout:
              enable: false
    Copy the code
  3. Turn off Hystrix when using Feign, this is not recommended

    feign:
      hystrix:
        enable: false
    Copy the code

Returns the processing of the image stream

If you return an image, it’s usually a byte array. But Contrller cannot return bytes directly, so the type returned by the called API should use Response.

Add a return image interface to the module created using the file upload above. Take the example of generating a QR code.

Some changes to cloud-openfeign- Fileupload-server

Add new dependencies and quickly generate qr codes using HuTool

		<dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.6.3</version>
        </dependency>
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>3.3.3</version>
        </dependency>
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-core</artifactId>
        </dependency>
Copy the code

Controller interface, here is simply generated a TWO-DIMENSIONAL code, two-dimensional code can also add more information. I won’t go into detail here, but there are many methods of QrCodeUtil of Hutool, and those who are interested can study them by themselves.

	@GetMapping(value = "/qrcode")
    public byte[] image() {
        return generateQrCode();
    }
    /** * first simply generate a URL qr code, pointing to Baidu *@return* /
    private byte[] generateQrCode() {
        return QrCodeUtil.generatePng("https://www.baidu.cn/".300.300);
    }
Copy the code

Some changes to cloud-openfeign- Fileupload-client

Adding a New dependency

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>

Copy the code

Feignclient adds a new interface

	@GetMapping("/qrcode")
    Response getQrCode(a);
Copy the code

For the modification of controller, to display pictures on the front page, the most commonly used is to return a URL to the page, but these are all stored pictures, but every time the verification code and QR code are generated, the server may not store them. So instead of returning a URL address, the return front end Base64 encoding is used for captchas. A QR code may return a byte stream and Base64 image based on HttpServletResponse, produces.

Here, using HttpServletResponse, add the method:

    @GetMapping("/qrcode")
    public void getQrCode(HttpServletResponse response) {
        Response res = fileUploadApiService.getQrCode();
        try {
            InputStream inputStream = res.body().asInputStream();
            response.setContentType(MediaType.IMAGE_PNG_VALUE);
            IOUtils.copy(inputStream,response.getOutputStream());
        } catch(IOException e) { e.printStackTrace(); }}Copy the code

Browser visit: http://localhost:8011/file/qrcode, and the result

Call passing token

Normally, the system has authentication and authentication function, whether JWT or security, when the external request to service A, is with the token, but this request in service A through Feign call service B, token loss will occur.

The solution is not difficult. When using Feign remote calls, carry the token in the request header. Normally, the token is placed in the request header.

Feign provides a RequestInterceptor that intercepts Feign’s requests by adding a token to the request header. For this part of the code, add it on cloud-OpenFeign-Consumer and cloud-OpenFeign-Provider.

Modify the cloud – openfeign – the provider

Modify the method to make it easier to present the results

	@PostMapping(value = "/update")
    public String updateOrder(@RequestBody Order order, HttpServletRequest request) {
        String token = request.getHeader("token");
        return "hello," + order.getName() + "" + "haha! I get a token: " + token;
    }
Copy the code

Modify the cloud – openfeign – consumer

Add an interceptor to implement feign.RequestInterceptor

@Component
public class FeignTokenInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        if (null == getHttpServletRequest()) {
            // You can record some logs here
            return;
        }
        // Pass the value corresponding to the obtained Token below
        requestTemplate.header("token", getHeaders(getHttpServletRequest()).get("token"));
    }

    private HttpServletRequest getHttpServletRequest(a) {
        try {
            return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        } catch (Exception e) {
            return null; }}/** * Feign interceptor intercepts the request to get the Token value **@param request
     * @return* /
    private Map<String, String> getHeaders(HttpServletRequest request) {
        Map<String, String> map = new LinkedHashMap<>();
        Enumeration<String> enumeration = request.getHeaderNames();
        while (enumeration.hasMoreElements()) {
            String key = enumeration.nextElement();
            String value = request.getHeader(key);
            map.put(key, value);
        }
        returnmap; }}Copy the code

Finally, start the service to start the test, test results: