文章目录
父pom(适用于SpringCloud Alibaba 系列):
<!-- 子模块继承后,提供作用:锁定版本,子模块不用再写groupId和version-->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.16.18</lombok.version>
<mysql.version>8.0.18</mysql.version>
<druid.version>1.1.16</druid.version>
<druid.spring.boot.starter.version>1.1.10</druid.spring.boot.starter.version>
<spring.boot.version>2.2.2.RELEASE</spring.boot.version>
<spring.cloud.version>Hoxton.SR1</spring.cloud.version>
<spring.cloud.alibaba.version>2.1.0.RELEASE</spring.cloud.alibaba.version>
<mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
<mybatis-spring-boot-starter.version>2.1.1</mybatis-spring-boot-starter.version>
<hutool-all.version>5.1.0</hutool-all.version>
</properties>
<!--子模块继承后,提供作用:锁定版本+子module不用groupId和version-->
<dependencyManagement>
<dependencies>
<!--springboot 2.2.2-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--Spring cloud Hoxton.SR1-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--Spring cloud alibaba 2.1.0.RELEASE-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.spring.boot.starter.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
<addResources>true</addResources>
</configuration>
</plugin>
</plugins>
</build>
<!--第三方maven私服-->
<repositories>
<repository>
<id>nexus-aliyun</id>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
1.服务提供方
pom
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency><dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
</dependencies>
yml
server:
port: 9001
spring:
application:
name: nacos-payment-provider
cloud:
nacos:
discovery:
server-addr: localhost:8848 #配置Nacos地址
management:
endpoints:
web:
exposure:
include: '*'
controller
@RestController
public class PaymentController {
@Value("${server.port}")
private String serverPort;
@GetMapping(value = "/payment/nacos/{id}")
public String getPayment(@PathVariable("id") Integer id) {
return "nacos registry, serverPort: " + serverPort + "\t id" + id;
}
}
Main
@EnableDiscoveryClient
@SpringBootApplication
public class PaymentMain9001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain9001.class,args);
}
}
2. 注册中心
3. 网关GateWay
pom
<dependencies>
<!-- 不要有 web 回jar包冲突-->
<!--新增gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.example</groupId>-->
<!-- <artifactId>cloud-api-common</artifactId>-->
<!-- <version>1.0-SNAPSHOT</version>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
yml
server:
port: 9527
spring:
application:
name: cloud-nacosgateway
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes:
- id: payment_routh #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://nacos-payment-provider # lb 开启负载均衡
predicates:
- Path=/payment/nacos/** #断言,路径相匹配的进行路由
Main
@EnableDiscoveryClient
@SpringBootApplication
public class GateWayNacos9527 {
public static void main(String[] args) {
SpringApplication.run(GateWayNacos9527.class, args);
}
}
测试
加入一台provider
成功访问到
5. GateWay基本概念
1. 路由
spring:
application:
name: cloud-nacosgateway
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes:
- id: payment_routh #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://nacos-payment-provider # 微服务名称
predicates:
- Path=/payment/nacos/** #断言,路径相匹配的进行路由
Java配置:
代表将 ip地址为10.1.1.1的访问转发到 down。。。。
2. 断言
predicates:
下面加个 -
可以添加多种断言
3. 过滤器
路由过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应。路由过滤器适用于特定路由。Spring Cloud Gateway包括许多内置的GatewayFilter工厂。
配置:
spring:
cloud:
gateway:
routes:
- id: add_request_header_route
uri: https://example.org
filters:
- AddRequestHeader=X-Request-red, blue
此清单将X-Request-red:blue标头添加到所有匹配请求的下游请求的标头中。
AddRequestHeader了解用于匹配路径或主机的URI变量。URI变量可以在值中使用,并在运行时扩展。
java config形式
使用ModifyRequestBody过滤器过滤器在网关向下游发送请求主体之前对其进行修改。
是否可以在这个config里面对权限进行认证呢?
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("rewrite_request_obj", r -> r.host("*.rewriterequestobj.org")
.filters(f -> f.prefixPath("/httpbin")
.modifyRequestBody(String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE,
(exchange, s) -> return Mono.just(new Hello(s.toUpperCase())))).uri(uri))
.build();
}
static class Hello {
String message;
public Hello() { }
public Hello(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
尝试通过代码的形式将转发的请求添加头信息:
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("route1", r -> r.path("/payment/nacos/header/**")
.filters(f->f.addRequestHeader("json", "123"))
.uri("lb://nacos-payment-provider")).build();
}
OAuth2 认证的时候可以转发这个地方,通过头信息来转发
4. 全局过滤器
当请求与路由匹配时,过滤Web处理程序会将的所有实例GlobalFilter和所有特定GatewayFilter于路由的实例添加到过滤器链中。该组合的过滤器链按org.springframework.core.Ordered接口排序,您可以通过实现该getOrder()方法进行设置。
@Bean
public GlobalFilter customFilter() {
return new CustomGlobalFilter();
}
public class CustomGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("custom global filter");
// if (false){
// return exchange.getResponse().setComplete();
// }
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -1;
}
}
由于Spring Cloud Gateway区分了执行过滤器逻辑的“前”阶段和“后”阶段,因此优先级最高的过滤器是“pre”
在这个里面有些api搞不太懂
最后贴一个官方的使用示范:
@RestController
@SpringBootApplication
public class DemogatewayApplication {
@RequestMapping("/hystrixfallback")
public String hystrixfallback() {
return "This is a fallback";
}
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
//@formatter:off
return builder.routes()
.route("path_route", r -> r.path("/get")
.uri("http://httpbin.org"))
.route("host_route", r -> r.host("*.myhost.org")
.uri("http://httpbin.org"))
.route("rewrite_route", r -> r.host("*.rewrite.org")
.filters(f -> f.rewritePath("/foo/(?<segment>.*)",
"/${segment}"))
.uri("http://httpbin.org"))
.route("hystrix_route", r -> r.host("*.hystrix.org")
.filters(f -> f.hystrix(c -> c.setName("slowcmd")))
.uri("http://httpbin.org"))
.route("hystrix_fallback_route", r -> r.host("*.hystrixfallback.org")
.filters(f -> f.hystrix(c -> c.setName("slowcmd").setFallbackUri("forward:/hystrixfallback")))
.uri("http://httpbin.org"))
.route("limit_route", r -> r
.host("*.limited.org").and().path("/anything/**")
.filters(f -> f.requestRateLimiter(c -> c.setRateLimiter(redisRateLimiter())))
.uri("http://httpbin.org"))
.route("websocket_route", r -> r.path("/echo")
.uri("ws://localhost:9000"))
.build();
//@formatter:on
}
@Bean
RedisRateLimiter redisRateLimiter() {
return new RedisRateLimiter(1, 2);
}
@Bean
SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) throws Exception {
return http.httpBasic().and()
.csrf().disable()
.authorizeExchange()
.pathMatchers("/anything/**").authenticated()
.anyExchange().permitAll()
.and()
.build();
}
@Bean
public MapReactiveUserDetailsService reactiveUserDetailsService() {
UserDetails user = User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build();
return new MapReactiveUserDetailsService(user);
}
public static void main(String[] args) {
SpringApplication.run(DemogatewayApplication.class, args);
}
}
Filter写法:
public class ThrottleGatewayFilter implements GatewayFilter {
private static final Log log = LogFactory.getLog(ThrottleGatewayFilter.class);
int capacity;
int refillTokens;
int refillPeriod;
TimeUnit refillUnit;
public int getCapacity() {
return capacity;
}
public ThrottleGatewayFilter setCapacity(int capacity) {
this.capacity = capacity;
return this;
}
public int getRefillTokens() {
return refillTokens;
}
public ThrottleGatewayFilter setRefillTokens(int refillTokens) {
this.refillTokens = refillTokens;
return this;
}
public int getRefillPeriod() {
return refillPeriod;
}
public ThrottleGatewayFilter setRefillPeriod(int refillPeriod) {
this.refillPeriod = refillPeriod;
return this;
}
public TimeUnit getRefillUnit() {
return refillUnit;
}
public ThrottleGatewayFilter setRefillUnit(TimeUnit refillUnit) {
this.refillUnit = refillUnit;
return this;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
TokenBucket tokenBucket = TokenBuckets.builder().withCapacity(capacity)
.withFixedIntervalRefillStrategy(refillTokens, refillPeriod, refillUnit)
.build();
// TODO: get a token bucket for a key
log.debug("TokenBucket capacity: " + tokenBucket.getCapacity());
boolean consumed = tokenBucket.tryConsume();
if (consumed) {
return chain.filter(exchange);
}
exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
return exchange.getResponse().setComplete();
}
}
其他详情见官方文档