网关功能:
SpringCloudGateway
作为SpringCloud
生态系统的网关,目标是为了代替zuul
,zuul
是基于Servlet的实现,属于阻塞式编程。而SpringCloudGateway则是基于Spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能。
Spring Cloud Gateway
底层使用了高性能的通信框架Netty
。
Gateway
由三部分组成:
Filter
(过滤器):Route
(路由):Predicate
(断言):引入依赖
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-gatewayartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
创建配置文件applicaion.yml
server:
port: 8070
spring:
application:
name: api-gateway
cloud:
#gateway的配置
gateway:
#路由配置 [路由 就是指定当请求满足什么条件的时候转到哪个微服务]
routes:
- id: order_route #路由的唯一标识,路由到order
uri: lb://order-service #需要转发的地址,lb指的是从nacos中按照名称获取微服务,并遵循负载均衡策略
#断言规则,就是路由转发要满足的条件
predicates:
- Path=/order-ser/** #当请求路径满足Path指定的规则时,才进行路由转发
# 当客户端访问http://localhost:8070/order-ser/order/add 会路由到↓
# http://localhost:8081/order-ser/order/add,这个无法访问,需要filters过滤下
filters: #过滤器,请求在传递过程中可以通过过滤器对其进行一定的修改
- StripPrefix=1 # 转发之前去掉第一层路由
# StripPrefix的操作会将上述http://localhost:8081/order-ser/order/add 路由到
# http://localhost:8081/order/add
# - id: stock_route
#配置nacos
nacos:
discovery:
server-addr: 127.0.0.1:8848
username: nacos
password: nacos
路由断言工厂Route Predicate Factory
Spring提供了11种基本的Predicate工厂:
applicaion.yml简单配置
server:
port: 8070
spring:
application:
name: api-gateway
cloud:
#gateway的配置
gateway:
discovery:
locator:
enabled: true #是否启动自动识别nacos服务
#配置nacos
nacos:
discovery:
server-addr: 127.0.0.1:8848
username: nacos
password: nacos
添加全局过滤器
package com.example.gateway.filters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
public class LogFilter implements GlobalFilter {
Logger log = LoggerFactory.getLogger(this.getClass());
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info(exchange.getRequest().getPath().value());
return chain.filter(exchange);
}
}
过滤器执行顺序
DefaultFilter、当前路由的过滤器、GlobalFilter
要启用 Reactor Netty 访问日志,请设置-Dreactor.netty.http.server.accessLogEnabled=true.
配置文件方式 application.yml
server:
port: 8070
spring:
application:
name: api-gateway
cloud:
#gateway的配置
gateway:
#跨域配置
globalcors:
cors-configurations:
'[/**]': # 允许跨域访问的资源
allowedOrigins: "*" #跨域允许来源
allowedMethods: #跨域允许方法
- GET
- POST
#路由配置 [路由 就是指定当请求满足什么条件的时候转到哪个微服务]
routes:
- id: order_route #路由的唯一标识,路由到order
uri: lb://order-service #需要转发的地址,lb指的是从nacos中按照名称获取微服务,并遵循负载均衡策略
#断言规则,就是路由转发要满足的条件
predicates:
# 当客户端访问http://localhost:8070/order/add 会路由到↓
# http://localhost:8081/order/add,这个无法访问,因为order服务添加上下午路径/myorder
# 需要filters过滤下
- Path=/order/** #当请求路径满足Path指定的规则时,才进行路由转发
filters:
- PrefixPath=/myorder # 添加前缀 对应微服务需要配置context-path
- CheckAuth=zhangsan
#配置nacos
nacos:
discovery:
server-addr: 127.0.0.1:8848
username: nacos
password: nacos
配置类方式
package com.example.gateway.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.util.pattern.PathPatternParser;
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsWebFilter(){
CorsConfiguration config = new CorsConfiguration();
config.addAllowedMethod("*"); //允许的method
config.addAllowedOrigin("*"); //允许的来源
config.addAllowedHeader("*"); //允许的请求头参数
//允许访问的资源
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**",config);
return new CorsWebFilter(source);
}
}
添加依赖
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-gatewayartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-alibaba-sentinel-gatewayartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
dependency>
测试代码
package com.example.order.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.concurrent.TimeUnit;
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private RestTemplate restTemplate;
@RequestMapping("/add")
public String add(){
System.out.println("下单成功");
String forObject = restTemplate.getForObject("http://stock-service/stock/reduck", String.class);
return "Hello World " + forObject;
}
@RequestMapping("/header")
public String header(@RequestHeader("X-Request-color") String color){
return color;
}
@RequestMapping("/flow")
public String flow(){
return "正常访问";
}
@RequestMapping("/flowThread")
public String flowThread() throws InterruptedException {
TimeUnit.SECONDS.sleep(2);
System.out.println("正常访问");
return "正常访问";
}
@RequestMapping("/err")
public String err(){
int a = 1/0;
return "err";
}
/**
* 热点规则,必须使用@SentinelResource
* @param id
* @return
*/
@RequestMapping("/get/{id}")
public String getById(@PathVariable("id") Integer id){
System.out.println("正常访问");
return "正常访问";
}
@RequestMapping("/get")
public String get(){
return "查询订单";
}
}
启动 sentinel 控制台,在控制台中进行测试