Nacos configuration management
Unified configuration management
- Configuration change hot update
Steps to hand over the configuration to Nacos management:
- Add configuration files in Nacos
- Introduce nacos config dependencies in microservices
- Add bootstrap.yml to the microservice, and configure the nacos address, current environment, service name, and file extension. These determine which file to read from nacos when the program starts
- Add configuration information in Nacos
- Fill in the configuration information in the pop-up form
- Configuration file id: [service name]-[profile].[suffix name], such as userservice-dev.yaml
- Grouping: default
- Format: currently supports yaml and properties
-
Introduce Nacos configuration management client dependencies:
<!--nacos配置管理依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
-
Add a bootstrap.yml file to the resource directory in userservice. This file is a bootstrap file with a higher priority than application.yml:
spring: application: name: userservice # 服务名称 profiles: active: dev # 环境 cloud: nacos: server-addr: localhost:8848 # nacos地址 config: file-extension: yaml # 文件后缀名
Inject the pattern.dateformat attribute into UserController in user-service for testing:
@Value("${pattern.dateformat}")
private String dateFormat;
@GetMapping("/now")
public String now() {
return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateFormat, Locale.CHINA));
}
Configure automatic refresh
After the configuration file in Nacos is changed, the microservice can perceive it without restarting. However, you need to implement the following two configurations:
-
Method 1: Add annotation @RefreshScope on the class where the variable injected by @Value is located
@Slf4j @RestController @RefreshScope @RequestMapping("/user") public class UserController { @Value("${pattern.dateformat}") private String dateFormat; ... }
-
Method 2: Use @ConfigurationProperties annotation (directly injected into a member variable of a certain class)
@Data @Component @ConfigurationProperties(prefix = "pattern") public class PatternProperties { private String dateFormat; }
Precautions:
- Not all configurations are suitable to be placed in the configuration center, which is troublesome to maintain
- It is recommended to put some key parameters and parameters that need to be adjusted at runtime into the nacos configuration center, which are generally custom configurations
Multi-environment shared configuration
When the microservice starts, it will read multiple configuration files from nacos:
- [spring.application.name]-[spring.profiles.active].yaml,例如:users
ervice-dev.yaml - [spring.application.name].yaml,例如: userservice.yaml
No matter how the profile changes, the [spring.application.name].yaml file will definitely be loaded,
so the multi-environment shared configuration can be written to this file
Priority of various configurations:
- service-name-profile.yaml > service-name.yaml > local-configuration
- userservice-dev-.yaml > userservice.yaml > local configuration file
Nacos cluster construction
In the Nacos production environment, it must be deployed as a cluster state
The basic steps to build a cluster:
-
Build the database and initialize the database table structure
Nacos default data is stored in the embedded database Derby, which is not a production-available database. The officially recommended best practice is to use a high-availability database cluster with a master-slave. Here, a single-point database is used as an example.
First create a new database, name it nacos, and then import the following SQL (the sql file is located in nacos\conf\nacos-mysql.sql)
CREATE TABLE `config_info` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', `data_id` varchar(255) NOT NULL COMMENT 'data_id', `group_id` varchar(255) DEFAULT NULL, `content` longtext NOT NULL COMMENT 'content', `md5` varchar(32) DEFAULT NULL COMMENT 'md5', `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', `src_user` text COMMENT 'source user', `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip', `app_name` varchar(128) DEFAULT NULL, `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段', `c_desc` varchar(256) DEFAULT NULL, `c_use` varchar(64) DEFAULT NULL, `effect` varchar(64) DEFAULT NULL, `type` varchar(64) DEFAULT NULL, `c_schema` text, PRIMARY KEY (`id`), UNIQUE KEY `uk_configinfo_datagrouptenant` (`data_id`,`group_id`,`tenant_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info'; /******************************************/ /* 数据库全名 = nacos_config */ /* 表名称 = config_info_aggr */ /******************************************/ CREATE TABLE `config_info_aggr` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', `data_id` varchar(255) NOT NULL COMMENT 'data_id', `group_id` varchar(255) NOT NULL COMMENT 'group_id', `datum_id` varchar(255) NOT NULL COMMENT 'datum_id', `content` longtext NOT NULL COMMENT '内容', `gmt_modified` datetime NOT NULL COMMENT '修改时间', `app_name` varchar(128) DEFAULT NULL, `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段', PRIMARY KEY (`id`), UNIQUE KEY `uk_configinfoaggr_datagrouptenantdatum` (`data_id`,`group_id`,`tenant_id`,`datum_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='增加租户字段'; /******************************************/ /* 数据库全名 = nacos_config */ /* 表名称 = config_info_beta */ /******************************************/ CREATE TABLE `config_info_beta` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', `data_id` varchar(255) NOT NULL COMMENT 'data_id', `group_id` varchar(128) NOT NULL COMMENT 'group_id', `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name', `content` longtext NOT NULL COMMENT 'content', `beta_ips` varchar(1024) DEFAULT NULL COMMENT 'betaIps', `md5` varchar(32) DEFAULT NULL COMMENT 'md5', `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', `src_user` text COMMENT 'source user', `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip', `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段', PRIMARY KEY (`id`), UNIQUE KEY `uk_configinfobeta_datagrouptenant` (`data_id`,`group_id`,`tenant_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_beta'; /******************************************/ /* 数据库全名 = nacos_config */ /* 表名称 = config_info_tag */ /******************************************/ CREATE TABLE `config_info_tag` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', `data_id` varchar(255) NOT NULL COMMENT 'data_id', `group_id` varchar(128) NOT NULL COMMENT 'group_id', `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id', `tag_id` varchar(128) NOT NULL COMMENT 'tag_id', `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name', `content` longtext NOT NULL COMMENT 'content', `md5` varchar(32) DEFAULT NULL COMMENT 'md5', `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', `src_user` text COMMENT 'source user', `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip', PRIMARY KEY (`id`), UNIQUE KEY `uk_configinfotag_datagrouptenanttag` (`data_id`,`group_id`,`tenant_id`,`tag_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_tag'; /******************************************/ /* 数据库全名 = nacos_config */ /* 表名称 = config_tags_relation */ /******************************************/ CREATE TABLE `config_tags_relation` ( `id` bigint(20) NOT NULL COMMENT 'id', `tag_name` varchar(128) NOT NULL COMMENT 'tag_name', `tag_type` varchar(64) DEFAULT NULL COMMENT 'tag_type', `data_id` varchar(255) NOT NULL COMMENT 'data_id', `group_id` varchar(128) NOT NULL COMMENT 'group_id', `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id', `nid` bigint(20) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`nid`), UNIQUE KEY `uk_configtagrelation_configidtag` (`id`,`tag_name`,`tag_type`), KEY `idx_tenant_id` (`tenant_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_tag_relation'; /******************************************/ /* 数据库全名 = nacos_config */ /* 表名称 = group_capacity */ /******************************************/ CREATE TABLE `group_capacity` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID', `group_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Group ID,空字符表示整个集群', `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值', `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量', `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值', `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数,,0表示使用默认值', `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值', `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量', `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_group_id` (`group_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='集群、各Group容量信息表'; /******************************************/ /* 数据库全名 = nacos_config */ /* 表名称 = his_config_info */ /******************************************/ CREATE TABLE `his_config_info` ( `id` bigint(64) unsigned NOT NULL, `nid` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `data_id` varchar(255) NOT NULL, `group_id` varchar(128) NOT NULL, `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name', `content` longtext NOT NULL, `md5` varchar(32) DEFAULT NULL, `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `src_user` text, `src_ip` varchar(50) DEFAULT NULL, `op_type` char(10) DEFAULT NULL, `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段', PRIMARY KEY (`nid`), KEY `idx_gmt_create` (`gmt_create`), KEY `idx_gmt_modified` (`gmt_modified`), KEY `idx_did` (`data_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='多租户改造'; /******************************************/ /* 数据库全名 = nacos_config */ /* 表名称 = tenant_capacity */ /******************************************/ CREATE TABLE `tenant_capacity` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID', `tenant_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Tenant ID', `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值', `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量', `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值', `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数', `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值', `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量', `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_tenant_id` (`tenant_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='租户容量信息表'; CREATE TABLE `tenant_info` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', `kp` varchar(128) NOT NULL COMMENT 'kp', `tenant_id` varchar(128) default '' COMMENT 'tenant_id', `tenant_name` varchar(128) default '' COMMENT 'tenant_name', `tenant_desc` varchar(256) DEFAULT NULL COMMENT 'tenant_desc', `create_source` varchar(32) DEFAULT NULL COMMENT 'create_source', `gmt_create` bigint(20) NOT NULL COMMENT '创建时间', `gmt_modified` bigint(20) NOT NULL COMMENT '修改时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`), KEY `idx_tenant_id` (`tenant_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info'; CREATE TABLE `users` ( `username` varchar(50) NOT NULL PRIMARY KEY, `password` varchar(500) NOT NULL, `enabled` boolean NOT NULL ); CREATE TABLE `roles` ( `username` varchar(50) NOT NULL, `role` varchar(50) NOT NULL, UNIQUE INDEX `idx_user_role` (`username` ASC, `role` ASC) USING BTREE ); CREATE TABLE `permissions` ( `role` varchar(50) NOT NULL, `resource` varchar(255) NOT NULL, `action` varchar(8) NOT NULL, UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE ); INSERT INTO users (username, password, enabled) VALUES ('nacos', '$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu', TRUE); INSERT INTO roles (username, role) VALUES ('nacos', 'ROLE_ADMIN');
-
Download nacos installation package
-
configure nacos
Enter the conf directory of nacos, modify the configuration file cluster.conf.example, rename it to cluster.conf, and add the content:
127.0.0.1:8845 127.0.0.1:8846 127.0.0.1:8847
Then modify the application.properties file and add the database configuration
spring.datasource.platform=mysql db.num=1 db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC db.user.0=root db.password.0=root
-
Start nacos cluster
Copy the nacos folder three times and name them: nacos1, nacos2, nacos3
Then modify the application.properties in the three folders respectively,
nacos1:
server.port=8845
nacos2:
server.port=8846
nacos3:
server.port=8847
Then start three nacos nodes respectively:
startup.cmd
-
nginx reverse proxy
Modify the conf/nginx.conf file, the configuration is as follows:
upstream nacos-cluster { server 127.0.0.1:8845; server 127.0.0.1:8846; server 127.0.0.1:8847; } server { listen 80; server_name localhost; location /nacos { proxy_pass http://nacos-cluster; } }
Then visit in the browser: http://localhost/nacos.
Modify the application.yml file configuration in the code as follows:
spring: cloud: nacos: server-addr: localhost:80 # Nacos地址
http client Feign
Problems with calling RestTemplate
Let's first look at the code we used to initiate remote calls using RestTemplate:
String url = "http: //userservice/user/" + order.getUserId();
User user = restTemplate.getFor0bject(url, User.class);
There are following problems:
- Poor code readability and inconsistent programming experience
- URLs with complex parameters are difficult to maintain
Feign's introduction
Feign is a declarative http client, official address: https://github.com/OpenFeign/feign
Its role is to help us elegantly implement the sending of http requests and solve the problems mentioned above.
Define and use Feign client
The steps to use Feign are as follows:
-
Import dependencies:
<!--feign客户端--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
-
Add annotations to the startup class of order-service to enable the function of Feign:
@MapperScan("cn.itcast.order.mapper") @SpringBootApplication @EnableFeignClients public class OrderApplication { ... }
-
Write a Feign client:
package cn.itcast.order.clients; import cn.itcast.order.pojo.User; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @FeignClient("userservice") public interface UserClient { @GetMapping("/user/{id}") User FindById(@PathVariable("id") Long id); }
-
Replace RestTemplate with Feign client
@Autowired private UserClient userClient; public Order queryOrderById(Long orderId) { // 1.查询订单 Order order = orderMapper.findById(orderId); // 2.用Feign远程调用 User user = userClient.findById(order.getUserId()); // 3.封装User到Order order.setUser(user); // 4.返回 return order; }
It is mainly based on the annotations of SpringMVC to declare the information of remote adjustment, such as:
- Service name: userservice
- Request method: GET
- Request path: /user/{id}
- Request parameter: Long id
- Return value type: User
Customize the configuration of Feign
Feign runs a custom configuration to override the default configuration. The configuration that can be modified is as follows:
Generally, what we need to configure is the log level.
There are two ways to configure Feign logs:
- Method 1: configuration file method
-
Globally effective:
feign: client: config: default: #这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置 loggerLevel: FULL #日志级别
-
partial effect
feign: client: config: userservice: #这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置 loggerLevel: FULL #日志级别
- Method 2: java code method
You need to declare a Bean first:
package cn.itcast.config;
import feign.Logger;
import org.springframework.context.annotation.Bean;
public class FeignClientConfiguration {
@Bean
public Logger.Level feignLogLevel() {
return Logger.Level.BASIC;
}
}
- Then if it is a global configuration, put it in the @EnableFeignClients annotation:
@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
@EnableFeignClients(defaultConfiguration = FeignClientConfiguration.class)
public class OrderApplication {
...
}
- If it is a partial configuration, put it in the @FeignClient annotation:
@FeignClient(value = "userservice", configuration= FeignClientConfiguration.class)
public interface UserClient {
@GetMapping("/user/{id}")
User findById(@PathVariable("id") Long id);
}
Feign performance optimization
The underlying client implementation of Feign:
- URLConnection: default implementation, does not support connection pool
- Apache HttpClient: support connection pool
- OKHttp: support connection pool
Therefore, optimizing the performance of Feign mainly includes:
- Use a connection pool instead of the default URLConnection
- log level, preferably basic or none
Feign performance optimization - connection pool configuration
Feign adds Httpclient support:
Import dependencies:
<!--HttpClient依赖-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
Configure the connection pool:
feign:
httpclient:
enabled: true # 支持HttpClient的开关
max-connections: 200 # 最大连接数
max-connections-per-route: 50 #单个路径的最大连接数
Best Practices for Feign
Method 1 (inheritance): Define a unified parent interface for the consumer's FeignClient and the provider's controller as a standard.
- Services Tightly Coupled
- Mappings in parent interface parameter lists are not inherited
Method 2 (extraction): Extract FeignClient as an independent module, and put the POJO related to the interface and the default Feign configuration into this module, and provide it to all consumers
Extract FeignClient
The steps to implement Best Practice 2 are as follows:
-
First create a module named feign-api, and then introduce feign's starter dependency
-
Copy the UserClient, User, and DefaultFeignConfiguration written in order-service to the feign-api project
-
Introduce the dependency of feign-api in order-service
-
Modify all the import parts related to the above three components in order-service, and change them to import the package in feign-api
When the defined FeignClient is not in the scope of SpringBootApplication's scan package, these FeignClients cannot be used. There are two ways to solve it:
-
Method 1: Specify the package where FeignClient is located
@EnableFeignclients(basePackages = "cn.itcast.feign.clients")
-
Method 2: specify FeignClient bytecode
@EnableFeignclients(clients = { Userclient.class})
Unified Gateway Gateway
Why do you need a gateway
Gateway function:
-
Identity authentication and permission verification
-
Service routing, load balancing
-
request throttling
The technical realization of the gateway
The implementation of the gateway in Spring Cloud includes two types:
- gateway
- zul
Zuul is a Servlet-based implementation and belongs to blocking programming. Spring Cloud Gateway is based on WebFlux provided in Spring 5, which is an implementation of responsive programming and has better performance.
Build gateway service
Steps to build a gateway service:
-
Create a new module and introduce the dependency of SpringCloudGateway and the service discovery dependency of nacos:
<!--nacos服务注册发现依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--网关gateway依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency>
-
Write routing configuration and nacos address
server: port: 10010 # 网关端口 spring: application: name: gateway # 服务名称cloud : cloud: nacos: server-addr: localhost:8848 # nacos地址 gateway: routes: # 网关路由配置 - id: user-service # 路由id,自定义,必须唯一 # uri: http ://127.0.0.1:8081 # 路由的目标地址 http就是固定地址 uri: lb://userservice # 路由的目标地址lb就是负载均衡,后面跟服务名称 predicates: # 路由断言,判断请求是否符合规则 - Path=/user/** # 路径断言,判断路径是否是以/user开头,如果是则符合 - id: order-service uri: lb://orderservice predicates: - Path=/order/**
Gateway construction steps:
- Create a project, introduce nacos service discovery and gateway dependencies
- Configure application.yml, including basic service information, nacos address, routing
Routing configuration includes:
- route id: the unique identifier of the route
- Routing destination (uri): the destination address of the routing, http stands for fixed address, lb stands for
load balancing based on service name - Routing assertion (predicates): rules for judging routing,
- Routing filters (filters): process the request or response
Route Predicate Factory Route Predicate Factory
The content that can be configured in the gateway route includes:
- route id: the unique identifier of the route
- uri: routing destination, supports both lb and http
- predicates: Routing assertion, to judge whether the request meets the requirements, if it meets the request, it will be forwarded to the routing destination
- filters: route filters, processing requests or responses
The assertion rules we write in the configuration file are just strings, these strings will be read and processed by the Predicate Factory, and transferred to the conditions for the way out judgment
Spring provides 11 basic Predicate factories:
Route filter GatewayFilter
GatewayFilter is a filter provided in the gateway, which can process the requests entering the gateway and the responses returned by microservices :
Spring provides 31 different route filter factories. For example:
More filters can be found in the document Spring Cloud Gateway Chinese Documentation (springdoc.cn)
default filter
If you want to take effect for all routes, you can write the filter factory under default. The format is as follows:
server:
port: 10010 # 网关端口
spring:
application:
name: gateway # 服务名称cloud :
cloud:
nacos:
server-addr: localhost:8848 # nacos地址
gateway:
routes: # 网关路由配置
- id: user-service # 路由id,自定义,必须唯一
# uri: http ://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
uri: lb://userservice # 路由的目标地址lb就是负载均衡,后面跟服务名称
predicates: # 路由断言,判断请求是否符合规则
- Path=/user/** # 路径断言,判断路径是否是以/user开头,如果是则符合
- id: order-service
uri: lb://orderservice
predicates:
- Path=/order/**
# filters: # 指定路由的过滤器
# - AddRequestHeader=MyKey,MyValue
default-filters: # 全局过滤器
- AddRequestHeader=MyKey,MyValue
Receive parameters:
@GetMapping("/{id}")
public User queryById(@PathVariable("id") Long id,
@RequestHeader(value = "MyKey", required = false) String myKey) {
System.out.println("myKey:" + myKey);
return userService.queryById(id);
}
Global Filter GlobalFilter
The role of the global filter is also to process all requests and microservice responses entering the gateway, which is the same as the role of GatewayFilter.
The difference is that GatewayFilter is defined through configuration, and the processing logic is fixed. The logic of GlobalFilter needs to be implemented by writing code yourself.
The way of definition is to implement the GlobalFilter interface.
- the case
Define a global filter to intercept and determine user identity
Requirements: Define a global filter, intercept requests, and determine whether the parameters of the request meet the following conditions.
- Whether there is authorization in the parameter,
- Whether the authorization parameter value is admin
If it is satisfied at the same time, let it go, otherwise block it
-
Step: Custom Filters
Customize the class, implement the GlobalFilter interface, and set the priority:
//@Order(-1) //设置优先级,也可以通过实现Ordered接口设置(此处采用接口设置) @Component public class AuthorizeFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { //1.获取请求参数 ServerHttpRequest request = exchange.getRequest(); MultiValueMap<String, String> params = request.getQueryParams(); //2.获取参数中的authorization参数 String author = params.getFirst("authorization"); //3.判断参数值是否等于admin if ("admin".equals(author)) { //4.是,放行 return chain.filter(exchange); } //5.否,拦截 //5.1设置状态码 exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); //5.2拦截请求 return exchange.getResponse().setComplete(); } //设置优先级 @Override public int getOrder() { return -1; } }
filter execution order
When a request enters the gateway, it will encounter three types of filters: current route filter, DefaultFilter, GlobalFilter
After requesting routing, the current routing filter, DefaultFilter, and GlobalFilter will be merged into a filter chain (collection), and each filter will be executed in turn after sorting
- Each filter must specify an int type order value, the smaller the order value, the higher the priority, and the higher the execution order .
- GlobalFilter specifies the order value by implementing the Ordered interface or adding the @Order annotation, which is specified by ourselves
- The order of routing filters and defaultFilter is specified by Spring, and the default is to increase from 1 according to the order of declaration.
- When the order values of the filters are the same, they will be executed in the order of defaultFilter > routing filter > GlobalFilter.
Cross domain problem handling
Cross-domain: Inconsistent domain names are cross-domain, mainly including:
- Different domain names: www.taobao.com and www.taobao.org and www.jd.com and miaosha.jd.com
- Same domain name, different ports: localhost:8080 and localhost:8081
- Different protocols: http and https
Cross-domain problem: The browser prohibits the originator of the request from making a cross-domain ajax request with the server, and the request is intercepted by the browser
Solution: CORS
The gateway also adopts the CORS scheme for cross-domain processing, and it only needs simple configuration to achieve:
spring:
cloud:
gateway:
globalcors: # 全局的跨域处理
add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
corsConfigurations:
'[/**]':
allowedOrigins: # 允许哪些网站的跨域请求
- "http://localhost:8090"
- "http://www.leyou.com"
allowedMethods: # 允许的跨域ajax的请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" # 允许在请求中携带的头信息
allowCredentials: true # 是否允许携带cookie
maxAge: 360000 # 这次跨域检测的有效期