This article is a summary of the video summary of SpringCloud micro-service combat, which involves

  1. Configure the Eureka Server and Eureka Client
  2. Eureka Server high availability
  3. There are two modes of communication between services: RestTemplate and Feign
  4. Install and use RabbitMQ
  5. Configure the use of the center
  6. Use of Spring Cloud Stream
  7. Various uses of the service gateway Zuul

As it is a class note, write a little random, big guys forgive me ~

Most of the techniques mentioned in this article will be used in one of my open source projects, where the back-end business logic has been basically written, except for permission verification, gateway configuration and post-optimization, for those interested.

Project address: github.com/cachecats/c…


About the command line

Start the SpringBoot project

java -jar test.jar
Copy the code

Start the SpringBoot project and specify a port

java -jar -Dserver.port=8899 test.jar
Copy the code

Start the SpringBoot project and specify a background run

nohup java -jar test.jar > /dev/null 2> &1 &
Copy the code

Check the process

ps -ef | grep eureka
Copy the code

Kill the process

kill- 9 processCopy the code

Install the project locally to the local Maven repository

 mvn -Dmaven.test.skip=true -U clean install
Copy the code

Second, Eureka Server

2.1 new

Choose CloudDiscovery -> Eureka Server

Note the SpringBoot version

2.2 configuration

Annotate the startup class Application

@EnableEurekaServer
Copy the code

Register the service in the configuration file application.yml

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8080/eureka/
Copy the code

Start the project, enter the browser address http://localhost:8080 to see the project started normally, and register yourself

ApplicationName is UNKNOWN. If you want to change the name of your application, do the following in application.yml

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8080/eureka/
spring:
  application:
    name: eureka
Copy the code

Restart the project, view in the browser, the name is displayed correctly

If you do not want the registry to appear in the registry, register-with-eureka: false

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8080/eureka/   Configure the default registration address
    register-with-eureka: false  Do not allow the service to be displayed in the app list
spring:
  application:
    name: eureka  Configure the application name
Copy the code

Three, had been the Client

3.1 Creating a Project

Choose CloudDiscovery -> Eureka Discovery

Notice The SpringBoot and SpringCloud versions are the same as the Server versions

3.2 configuration

  1. The entranceApplicationAdd annotations@EnableDiscoveryClient
@SpringBootApplication
@EnableDiscoveryClient
public class ClientApplication {

    public static void main(String[] args) { SpringApplication.run(ClientApplication.class, args); }}Copy the code
  1. Configuring the Server Address
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
spring:
  application:
    name: client
Copy the code
  1. User-defined link address. After configuration, the browser address will becomehttp://clientname:8080/
eureka:
  instance:
    hostname: clientName
Copy the code
  1. If the client service is restarted frequently, the following warning is displayed

This is SpringCloud’s self-protection mechanism, which is to treat the service as online regardless of whether it is online or not. This function can be turned off in the development environment for debugging purposes, but must be turned on in the production environment.

Do the following in applicaitono. Yml of the server

eureka:
  server:
    enable-self-preservation: false
Copy the code

High availability of Eureka Server

Currently, clients register with a Eureka Server. What if the Server fails?

Multiple Eureka Servers can be started and registered with each other.

Here is a demonstration of starting three Eureka servers to register with each other and registering clients with each of the three servers.

Configure the server

Start EurekaApplication, EurekaApplication2 and EurekaApplication3 on ports 8761, 8762 and 8763 respectively. Configure the addresses of the other two services in applicaton.yml for each of the three services.

As EurekaApplication with http://localhost:8762/eureka/, http://localhost:8763/eureka/,

EurekaApplication2 with http://localhost:8761/eureka/, http://localhost:8763/eureka/,

EurekaApplication3 with http://localhost:8761/eureka/, http://localhost:8762/eureka/,

The EurekaApplication’s applicaton.yml is as follows:

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8762/eureka/,http://localhost:8763/eureka/
Copy the code

This correlates the three services to each other.

Configure the client

Then add all three service addresses to the Client’s applicaton.yml file

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/,http://localhost:8763/eureka/
Copy the code

The EurekaApplication is registered to 8762 and 8763. As long as one of the three servers is still alive, the service will not hang.

5. Inter-application communication

There are two main communication modes for inter-application communication:

HTTP stands for: SpringCloud

RPC representative: Dubbo

Two restful invocation methods between services in SpringCloud

  • RestTemplate
  • Feign

5.1 RestTemplate way

There are three methods of the RestTemplate call, described below.

First write a Controller exposed interface in the application that will provide the data. Call it ServerController

@RestController
@RequestMapping("/product")
public class ServerController {

    @GetMapping("/msg")
    public String getMsg(a){
        return "I am product msg"; }}Copy the code

Then write a Controller called ClientController in the application that needs to receive data

5.1.1 method a

Use RestTemplate directly to manually write the URL that provides the data

@RestController
@RequestMapping("/order")
@Slf4j
public class ClientController {

    @GetMapping("/getmsg")
    public String getMsg(a){
        RestTemplate restTemplate = new RestTemplate();
        String result = restTemplate.getForObject("http://localhost:8080/product/msg", String.class);
        log.info("result={}", result);
        returnresult; }}Copy the code

5.1.2 method 2

Instead of manually entering the URL address, use LoadBalancerClient to dynamically obtain the url by application name, and then use RestTemplate.

loadBalancerClient.choose(“product”); The product is the application ID that provides the data

@RestController
@RequestMapping("/order")
@Slf4j
public class ClientController {

    @Autowired
    LoadBalancerClient loadBalancerClient;

    @GetMapping("/getmsg")
    public String getMsg(a){
        ServiceInstance serviceInstance = loadBalancerClient.choose("product");
        String url = String.format("http://%s:%s/product/msg", serviceInstance.getHost(), serviceInstance.getPort());
        RestTemplate restTemplate = new RestTemplate();
        String result = restTemplate.getForObject(url, String.class);
        returnresult; }}Copy the code

5.1.3 method 3

Use the @ LoadBalanced annotation

New RestTemplateConfig class

@Component
public class RestTemplateConfig {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(a){
        return newRestTemplate(); }}Copy the code

It is then used in ClientController.

restTemplate.getForObject(“http://product/product/msg”, String.class); The two products in the URL, the first representing the application name and the second the ADDRESS of the API. If the API address is/ABC, the URL is http://product/abc

@RestController
@RequestMapping("/order")
@Slf4j
public class ClientController {

    @Autowired
    RestTemplate restTemplate;
    
    @GetMapping("/getmsg")
    public String getMsg(a){
        String result = restTemplate.getForObject("http://product/product/msg", String.class);
        returnresult; }}Copy the code

5.2 Feign way

There are several steps to using Feign

Step 1: Introduce dependencies

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

Pay attention to

One problem is that some videos and articles cite the spring-cloud-starter-feign dependency. I used the same dependency in the beginning, but it didn’t work. Go to the Maven repository mvnrepository.com/, search spring-Cloud-starter-feign, and find the following:

Spring Cloud Starter Feign (deprecated, please use spring-cloud-starter-openfeign)

To say that spring-cloud-starter-OpenFeign is deprecated, use spring-cloud-starter-OpenFeign.

I’m using a higher version of SpringCloud, which may not support Spring-Cloud-starter-feign anymore.

Step 2: Configure the @enableFeignClients annotation

Configure the @enableFeignClients annotation in the entry class of the application

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

If @enableFeignClients cannot be found, check that the dependency is cited correctly and the version is correct.

Step 3: Create an encapsulation interface

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;

@FeignClient(name = "product")
@Component
public interface ProductClient {

    @GetMapping("/product/msg")
    String getMsg(a);
}
Copy the code

Interface annotation @feignClient, parentheses name = “product” to declare the application named product to find data (the application name is case-insensitive).

@getMapping (“/product/ MSG “) Specify the request mode and path.

So the getMsg() method is asking for a string with API /product/ MSG in the product application.

Step 4: Invoke

@RestController
@RequestMapping("/order")
@Slf4j
public class ClientController {

    @Autowired
    ProductClient productClient;

    @GetMapping("/getmsg")
    public String getMsg(a){
        returnproductClient.getMsg(); }}Copy the code

Inject the ProductClient created in step 3 and call the methods defined in the interface directly.

If I inject the ProductClient editor here, I will get an error, but it does not affect compilation.

Could not autowire. No beans of 'ProductClient' type found
Copy the code

I added an @Component annotation to ProductClient when it didn’t look right.

Feign:

  • Declarative REST client (pseudo RPC)
  • Interface-based annotations are used

Install RabbitMQ

Install RabbitMQ with Docker

Open the RabbitMQ official download page www.rabbitmq.com/download.ht… Docker

Click the Docker Image link to go to the details page

As you can see the latest version is 3.7.7, copy 3.7.7-management, type the following code on the command line and run it

docker run -d--hostname my-rabbit -P 5672:5672 -p 15672:15672 RabbitMQ :3.7.7- ManagementCopy the code

Use Docker PS to see the container we are running

Solo-mac:~ Solo $docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 345859e88EAD RabbitMQ :3.7.7- Management"Docker - entrypoint. S..."2 minutes ago Up 2 minutes 4369/ TCP, 5671/ TCP, 0.0.0.0:5672->5672/ TCP, 15671/ TCP, 25672/ TCP, 0.0.0.0:15672 - > 15672 / TCP goofy_volhardCopy the code

Enter http://localhost:15672 to start RabbitMQ. For the first time, you will be asked to enter the username and password, which are both guest

The RabbitMQ installation is complete.

7. Configuration center

7.1 Configuring the Central Server

  1. New project Config

    Check Cloud Config -> Config Server and Cloud Discovery -> Eureka DiscoveryCopy the code
  2. Add annotations to the startup class

    @SpringBootApplication
    @EnableDiscoveryClient
    @EnableConfigServer
    public class ConfigApplication {
    
        public static void main(String[] args) { SpringApplication.run(ConfigApplication.class, args); }}Copy the code
  3. Create a new project on Github or in the code cloud and upload the Application. Yml configuration file for the Order project to test.

  4. Configure the application.yml file for the project

    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8761/eureka/
    server:
      port: 8081
    spring:
      application:
        name: config
      cloud:
        config:
          server:
            git:
              uri: https://gitee.com/xxxxxxx
              username: xxxxxx
              password: xxxxxx
              basedir: xxxxxx  # Local path
    Copy the code

    The uri is the address of the warehouse, and the username and password are the username and password of the warehouse

  5. Start the project after configuration is complete, can see up project registration in the registry, the browser to http://localhost:8081/order-a.yml, can also be read properly on the git config file.

    The suffix for the access address input is ‘/order-a.yml’, as explained here.

    /{name}-{profiles}.yml /{label}/{name}-{profiles}.yml name: service name, where order profiles environment label branch (branchCopy the code

7.2 Configuring the Central Client

Use the Order project as the client

  1. In the Server module of orderpom.xmlAdd to fileconfig-clientRely on
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-client</artifactId>
</dependency>
Copy the code
  1. Rename application.yml to bootstrap.yml

  2. Configure the bootstrap. Yml

    spring:
      application:
        name: order
      cloud:
        config:
          discovery:
            enabled: true
            service-id: config  Configure the application name of the central server
          profile: dev
    
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8761/eureka/
    Copy the code

After the configuration, start the project and it can run normally.

Note:

  1. Don’t forget to change the profile namebootstrap.yml
  2. Configure eureka’s service-URL in the local configuration file instead of reading it from config because it will not be found if eureka’s port number is not the default 8761.
  3. If there is one on Gitorder.yml.order-dev.ymlIs configuredorder-dev.ymlThat will also load by default when it loadsorder.ymlAnd merge the two files. Using this characteristic, can be inorder.ymlWrite common configuration in.

7.3 Spring Cloud Bus Automatically Refreshes Configurations

7.3.1 Config Project Add spring Cloud Bus dependencies

Add spring Cloud Bus dependencies to the Config project

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

Start the project and check on the RabbitMQ console. If there is a connection, the configuration is successful.

7.3.2 Order project adds spring Cloud Bus dependencies

Add a dependency to order’s server module

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

Run RabbitMQ and two connections appear

7.3.3 Configuring Automatic Refreshing

Configure the application.yml file of the Config project to expose the bus-Refresh interface

management:
  endpoints:
    web:
      exposure:
        include: "*"
Copy the code

Create a new controller in order to read the env field in the remote configuration

Value indicates the configuration
@RestController
@RequestMapping("/env")
@RefreshScope
public class EnvController {

    @Value("${env}")
    private String env;

    @GetMapping("/print")
    public String print() {returnenv; }}Copy the code

Note that the @refreshScope annotation must be added, otherwise the configuration will not automatically refresh

Start again two projects, visit http://localhost:8899/env/print and get the value of the result is configured on the git env.

The value of the changes on the git env to send a post request http://127.0.0.1:8081/actuator/bus-refresh to refresh the message queue, Refresh again http://localhost:8899/env/print will not restart the project but env value has changed.

The prefix mode is configured

Git configuration

env: dev5

girl:
  name: lili
  age: 18
Copy the code

A new kind of GirlConfig

@Data
@Component
@ConfigurationProperties("girl")
@RefreshScope
public class GirlConfig {

    private String name;

    private Integer age;
}
Copy the code

New GirlController

@RestController
public class GirlController {

    @Autowired
    GirlConfig girlConfig;

    @GetMapping("girl/print")
    public String print(a){
        return "name= " + girlConfig.getName() + ", age= "+ girlConfig.getAge(); }}Copy the code

Browser enter http://localhost:8899/girl/print, get results name = lili, age = 18.

To change the configuration of the git as above, send a post request to http://127.0.0.1:8081/actuator/bus-refresh to refresh the message queue, you can see the result also follow changes.

If send request http://127.0.0.1:8081/actuator/bus-refresh the return value is 500, that is the bus didn’t match well. The last possible reason is a version problem, change the SpringBoot version to 2.0.0. build-snapshot and SpringCloud version to finchley.build-snapshot.

Basic use of RabbitMQ

Demonstrate this in the Order project

Configure rabbitMQ information in the configuration file. These configurations can be placed on remote Git

spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
Copy the code

8.1 Basic Usage

There are three basic uses for receiving messages

Method 1: Queues must be declared in advance

  1. Start by creating a queue in the RabbitMQ consolemyQueue
  2. Then create the message receiver and print the message on the console after receiving it
/** * RabbitMQ message receiver */
@Slf4j
@Component
public class MqReceiver {

    @RabbitListener(queues = "myQueue")
    public void process(String msg){
        log.info("reveicer: "+ msg); }}Copy the code
  1. To create a message sender, write a method in the test class for simplicity

    /** * RabbitMQ message sender */
    @Component
    public class RabbitMQTest extends OrderApplicationTests {
    
        @Autowired
        AmqpTemplate amqpTemplate;
    
        @Test
        public void test1(a){
            amqpTemplate.convertAndSend("myQueue"."now " + newDate()); }}Copy the code

Run the test, and the console successfully prints out the received message.

Method 2: Automatically create a queue

Delete the queue created in method 1, myQueue, and change the sender

@RabbitListener(queuesToDeclare = @Queue("myQueue"))
public void process(String msg){
	log.info("reveicer: " + msg);
}
Copy the code

Using queuesToDeclare automatically creates queues.

Method 3: Automatically create a queue and bind queue to Exchange

I’m going to delete myQueue, I’m going to change the sender, I’m going to change the receiver

@RabbitListener(bindings = @QueueBinding(
        value = @Queue("myQueue"),
        exchange = @Exchange("myExchange")))public void process(String msg){
    log.info("reveicer: " + msg);
}
Copy the code

8.2 Message Group

Suppose the order service has two groups, digital vendors and fruit vendors. After the order is placed, the computer order is sent to the digital supplier, and the fruit order is sent to the fruit supplier. Both vendors receive their own messages.

The receiver

    /** * Digital vendors receive messages *@param msg
     */
    @RabbitListener(bindings = @QueueBinding(
            exchange = @Exchange("myOrder"),
            key = "computer",
            value = @Queue("computerOrder")))public void processComputer(String msg){
        log.info("computerOrder reveicer: " + msg);
    }

    /** * Fruit vendor receives message *@param msg
     */
    @RabbitListener(bindings = @QueueBinding(
            exchange = @Exchange("myOrder"),
            key = "fruit",
            value = @Queue("fruitOrder")))public void processFruit(String msg){
        log.info("fruitOrder reveicer: " + msg);
    }
Copy the code

Message sender

@Test
public void send(){
	amqpTemplate.convertAndSend("myOrder"."computer"."now " + new Date());
}
Copy the code

This is a computer order, convertAndSend() exchange, routingKey, and message

Only computerOrder received the message after sending it.

Check the RabbitMQ console and you can see the relationship between exchanges and queues

Spring Cloud Stream

Spring Cloud Stream is a framework for building highly scalable event-driven microservices connected with shared messaging systems.
Copy the code

Spring Cloud Stream currently supports only RabbitMQ and Kafka messaging middleware

9.1 Procedure

The following shows the use of Spring Cloud Stream with RabbitMQ

  1. Introduction of depend on

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-stream-rabbit</artifactId> 
    </dependency>
    Copy the code
  2. Configure RabbitMQ as in the previous section

    spring:
      rabbitmq:
        host: localhost
        port: 5672
        username: guest
        password: guest
    Copy the code
  3. Create the interface StreamClient

    import org.springframework.cloud.stream.annotation.Input;
    import org.springframework.cloud.stream.annotation.Output;
    import org.springframework.messaging.MessageChannel;
    import org.springframework.messaging.SubscribableChannel;
    
    public interface StreamClient {
    
        String INPUT = "messageInput";
        String OUTPUT = "messageOut";
    
        @Input(INPUT)
        SubscribableChannel input(a);
    
        @Output(OUTPUT)
        MessageChannel output(a);
    
    }
    Copy the code
  4. Create the message receiver, which receives the string first

    @Component
    @EnableBinding(StreamClient.class)
    @Slf4j
    public class StreamReceiver {
    
        @StreamListener(StreamClient.OUTPUT)
        public void process(String obj){
            log.info("StreamReceiver: "+ obj); }}Copy the code
  5. Create a message sender

    import com.solo.order.message.StreamClient;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.messaging.support.MessageBuilder;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    import java.util.Date;
    
    @RestController
    public class SendMessageController {
    
        @Autowired
        private StreamClient streamClient;
    
        @GetMapping("/sendMessage")
        public void send(a) {
            String message = "now: " + newDate(); streamClient.output().send(MessageBuilder.withPayload(message).build()); }}Copy the code

    Note that MessageBuilder does not mislead packages

9.2 Message Group

If multiple instances are started at the same time, it is possible for multiple instances to receive messages. To avoid this problem, you can group messages.

Add it to the configuration file

spring:
  cloud:
    # Message grouping
    stream:
      bindings:
        messageInput:  # define the queue name
          group: order The group name is optional
Copy the code

9.3 Sending Receiving Objects

Transforming the message receiver

/** * Receive object *@param dto
*/
@StreamListener(StreamClient.OUTPUT)
public void process(OrderDTO dto){
	log.info("StreamReceiver: " + dto);
}
Copy the code

Transform the message sender

/** * send object */
@GetMapping("/sendMessage")
public void send(a) {
    OrderDTO dto = new OrderDTO();
    dto.setOrderId("12345678");
    streamClient.output().send(MessageBuilder.withPayload(dto).build());
}
Copy the code

If you want to see the serialized JSON string instead of the object name on the MQ console, change the configuration as follows

 spring:
  cloud:
    # Message grouping
    stream:
      bindings:
        messageInput:  # define the queue name
          group: order The group name is optional
 		  content-type: application/json  Let MQ display JSON strings instead of objects
Copy the code

Add the content-type: application/json

9.4 Responding to Messages Received

Add two interfaces to StreamClient

public interface StreamClient {

    String INPUT = "messageInput";
    String OUTPUT = "messageOut";
    String INPUT2 = "messageInput2";
    String OUTPUT2 = "messageOut2";

    @Input(INPUT)
    SubscribableChannel input();

    @Output(OUTPUT)
    MessageChannel output();

    @Input(INPUT2)
    SubscribableChannel input2();

    @Output(OUTPUT2)
    MessageChannel output2();

}
Copy the code

The message receiver makes the following changes

@StreamListener(StreamClient.OUTPUT)
@SendTo(StreamClient.OUTPUT2)
public String process(OrderDTO dto){
    log.info("StreamReceiver: " + dto);
    return "Received...";
}

@StreamListener(StreamClient.OUTPUT2)
public void process2(String msg){
	log.info("StreamReceiver2: " + msg);
}
Copy the code

Basically add an @sendto (streamClient.output2) annotation and return the desired value. Define a receiver to receive StreamClient.output2.

Ten, Redis installation and simple use

10.1 installation

Install and start with Docker

docker run -dRedis: 6379-6379 - p 4.0.8Copy the code

Redis visualization tool for MAC: Redis Desktop Manager, RDM for short

10.2 the use of

Add dependencies first

 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-data-redis</artifactId>
 </dependency>
Copy the code

Then configure the redis address and port number

  spring:
    redis:
      host: localhost
      port: 6379
Copy the code

11. Service gateway Zuul

11.1 introduction

Elements of a service gateway

  • Stability, high availability
  • Performance, concurrency
  • security
  • scalability

Common Gateway schemes

  • Nginx + Lua
  • Kong based on Nginx + Lua
  • Tyk
  • Spring Cloud Zuul

The characteristics of Zuul

  • Route + Filter
  • The core is a series of filters

Zuul’s four filter apis

  • Front (Pre)
  • Route
  • Post
  • Error

11.2 Use Zuul to implement simple routing and forwarding

Create a project api-gateway, check Cloud Config -> Config Client, CloudDiscovery -> Eureka Discovery, Cloud Routing -> Zuul. Click Next to complete the creation

Change the application.properties file to bootstrap.yml and do the following

spring:
  application:
    name: api-gateway

  cloud:
    config:
      discovery:
        enabled: true
        service-id: config
      profile: dev

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
Copy the code

Add the @enableZuulProxy annotation to the entry class

@SpringBootApplication
@EnableZuulProxy
public class ApiGatewayApplication {

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

Start a project on port 9000 and you can access the API of other projects through the gateway

If you want to access the product the product/project list interface, directly in the browser to enter http://localhost:9000/product/product/list.

The access format is http://localhost:9000/ application ID/API address

11.3 User-defined Routes

The bootstrap. Yml added

zuul:
  routes:
    myProduct:  # Self-defined name
      path: /myProduct/**
      serviceId: product
Copy the code

Can be accessed through http://localhost:9000/myProduct/product/list the above interface

Concise writing

zuul:
  routes:
    product: /myProduct/**
Copy the code

11.4 Excluding Some Routes

Exclude /product/list so that it cannot be accessed

zuul:
  routes:
  # Introduction writing method
    product: /myProduct/**
  # Exclude certain routes
  ignored-patterns:
    - /**/product/list
Copy the code

11.5 Cookies and Dynamic Routing

Read the Cookie

Cookies are filtered by default. If you want to get cookies, set sensitiveHeaders: to null

zuul:
  routes:
    myProduct:
      path: /myProduct/**
      serviceId: product
      sensitiveHeaders: 
Copy the code

Set the global sensitive header

zuul:
  Set the global sensitive header
  sensitive-headers:
Copy the code

Dynamically Configuring Routes

Move the zuul configuration to Git by creating api-gateway-dev.yml

Create a configuration class or prefix the configuration directly on the entry class

@SpringBootApplication
@EnableZuulProxy
public class ApiGatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(ApiGatewayApplication.class, args);
    }

    @ConfigurationProperties("zuul")
    @RefreshScope
    public ZuulProperties ZuulProperties(a){
        return newZuulProperties(); }}Copy the code

11.6 Pre and Post Filters

Token verification is implemented using the Pre filter

The following uses Zuul’s Pre filter to verify the requested token

New TokenFilter

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;

import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;

@Component
public class TokenFilter extends ZuulFilter {

    @Override
    public String filterType(a) {

        return PRE_TYPE;
    }

    @Override
    public int filterOrder(a) {
        return PRE_DECORATION_FILTER_ORDER - 1;
    }

    @Override
    public boolean shouldFilter(a) {
        return true;
    }

    @Override
    public Object run(a) throws ZuulException {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        // It can be retrieved from the url
        String token = request.getParameter("token");
        if (StringUtils.isEmpty(token)){
            requestContext.setSendZuulResponse(false);
            requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
        }
        return null; }}Copy the code

A request without a token will report a 401 error.

Add content to the return header with a Post filter

New AddResponseFilter

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletResponse;
import java.util.UUID;

@Component
public class AddResponseFilter extends ZuulFilter {

    @Override
    public String filterType(a) {
        return FilterConstants.POST_TYPE;
    }

    @Override
    public int filterOrder(a) {
        return FilterConstants.SEND_RESPONSE_FILTER_ORDER - 1;
    }

    @Override
    public boolean shouldFilter(a) {
        return true;
    }

    @Override
    public Object run(a) throws ZuulException {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletResponse response = requestContext.getResponse();
        response.addHeader("X-Foo", UUID.randomUUID().toString());
        return null; }}Copy the code

After adding x-foo to the return header, the restart project request interface found that the value was successfully added

11.7 Zuul current limit

import com.google.common.util.concurrent.RateLimiter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.exception.ZuulException;
import com.solo.apigateway.exception.RateLimitException;

import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SERVLET_DETECTION_FILTER_ORDER;

/** * current limiting interceptor. Token bucket, implemented with Google's Guava */
public class RateLimitFilter extends ZuulFilter {

    public static final RateLimiter RATE_LIMITER = RateLimiter.create(100);

    @Override
    public String filterType(a) {
        return PRE_TYPE;
    }

    @Override
    public int filterOrder(a) {
        return SERVLET_DETECTION_FILTER_ORDER - 1;
    }

    @Override
    public boolean shouldFilter(a) {
        return true;
    }

    @Override
    public Object run(a) throws ZuulException {
        if (RATE_LIMITER.tryAcquire()){
            throw new RateLimitException();
        }
        return null; }}Copy the code

Xii. Zuul authentication and adding user services

To be perfect

Zuul cross domain

Cross-domain problems can be resolved in a variety of ways, from annotations on a single interface to a unified approach on the Zuul gateway

13.1 Adding Annotations to Interfaces for Cross-domain implementation

Adding the @Crossorigin annotation to the interface makes it cross-domain

13.2 Zuul solves cross-domain

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

import java.util.Arrays;

/** * Cross-domain configuration */
@Configuration
public class CorsConfig {

    @Bean
    public CorsFilter corsFilter(a) {
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true); // Whether cookies are supported across domains
        config.setAllowedHeaders(Arrays.asList("*"));
        config.setAllowedOrigins(Arrays.asList("*"));
        config.setAllowedMethods(Arrays.asList("*"));
        config.setMaxAge(300l); // Cache time. During this time period, the same cross-domain request will not be checked

        source.registerCorsConfiguration("/ * *", config);
        return newCorsFilter(source); }}Copy the code

As the open source project goes on, I will write many articles to introduce these technologies in detail, welcome to pay attention to ~

Project address: github.com/cachecats/c…