Spring Cloud Gateway 建立在Spring Boot 2.x、Spring WebFlux和Project Reactor之上。因此,当您使用 Spring Cloud Gateway 时,您所知道的许多熟悉的同步库(例如 Spring Data 和 Spring Security)和模式可能并不适用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<properties>
<spring-cloud.version> 2021.0.4</spring-cloud.version>
</properties>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-gateway -->
<dependency>
<groupId> org.springframework.cloud</groupId>
<artifactId> spring-cloud-starter-gateway</artifactId>
</dependency>
<dependencyManagement>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies -->
<dependency>
<groupId> org.springframework.cloud</groupId>
<artifactId> spring-cloud-dependencies</artifactId>
<version> ${spring-cloud.version}</version>
<type> pom</type>
<scope> import</scope>
</dependency>
</dependencies>
</dependencyManagement>
词汇表
Predicate 网关的基本构建块。它由 ID、目标 URI、谓词集合和过滤器集合定义。如果聚合谓词为真,则匹配路由。
Predicate 这是一个Java 8 函数谓词。输入类型是 Spring Framework ServerWebExchange
。这使您可以匹配来自 HTTP 请求的任何内容,例如标头或参数。
Filter 使用特定工厂构建的 GatewayFilter
实例。在这里,您可以在发送下游请求之前或之后修改请求和响应。
a high-level overview of how Spring Cloud Gateway works
路由
StripPrefix参数表示在将请求发送到下游之前从请求中剥离的路径个数。
1
2
3
4
5
6
7
8
9
10
spring :
cloud :
gateway :
routes :
- id : route-svc-user
uri : lb://svc-user # 服务注册ID
predicates :
- Path=/user/**
filters :
- StripPrefix=1
GlobalFilter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@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" );
return chain . filter ( exchange );
}
@Override
public int getOrder () {
return - 1 ;
}
}
网关全局异常处理 实现 ErrorWebExceptionHandler
Spring Cloud Gateway 常见的方法有 实现自己的 DefaultErrorWebExceptionHandler 或 仅实现 ErrorAttributes。
重写 ErrorWebExceptionHandler#getRoutingFunction :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
@Component
public class GlobalErrorAttributes extends DefaultErrorAttributes {
@Override
public Map < String , Object > getErrorAttributes (
ServerRequest request , ErrorAttributeOptions options ) {
Throwable error = super . getError ( request );
Map < String , Object > map = super . getErrorAttributes ( request , options );
map . put ( "message" , error . getMessage ());
return map ;
}
}
@Component
@Order (- 2 )
public class GlobalErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {
public GlobalErrorWebExceptionHandler (
GlobalErrorAttributes gea ,
ApplicationContext applicationContext ,
ServerCodecConfigurer serverCodecConfigurer ) {
super ( gea , new WebProperties . Resources (), applicationContext );
super . setMessageWriters ( serverCodecConfigurer . getWriters ());
super . setMessageReaders ( serverCodecConfigurer . getReaders ());
}
/**
* 渲染html或json
*
* @param errorAttributes
* @return
*/
@Override
protected RouterFunction < ServerResponse > getRoutingFunction (
final ErrorAttributes errorAttributes ) {
return RouterFunctions . route ( RequestPredicates . all (), this :: renderErrorResponse );
}
private Mono < ServerResponse > renderErrorResponse ( final ServerRequest request ) {
final Map < String , Object > errorPropertiesMap =
getErrorAttributes ( request , ErrorAttributeOptions . defaults ());
return ServerResponse . status ( HttpStatus . BAD_REQUEST )
. contentType ( MediaType . APPLICATION_JSON )
. body ( BodyInserters . fromValue ( errorPropertiesMap ));
}
}
重写 ErrorWebExceptionHandler#handle :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
@Order (- 1 )
@Configuration
public class GatewayExceptionHandler implements ErrorWebExceptionHandler {
private static final Logger log = LoggerFactory . getLogger ( GatewayExceptionHandler . class );
private ObjectMapper objectMapper ;
@Autowired
public void setObjectMapper ( ObjectMapper objectMapper ) {
this . objectMapper = objectMapper ;
}
@Override
public Mono < Void > handle ( ServerWebExchange exchange , Throwable ex ) {
ServerHttpResponse response = exchange . getResponse ();
if ( exchange . getResponse (). isCommitted ()) {
return Mono . error ( ex );
}
String msg ;
if ( ex instanceof NotFoundException ) {
msg = "服务未找到" ;
} else if ( ex instanceof ResponseStatusException ) {
ResponseStatusException responseStatusException = ( ResponseStatusException ) ex ;
msg = responseStatusException . getMessage ();
} else {
// "内部服务器错误"
msg = ex . getLocalizedMessage ();
}
log . error ( "[网关异常处理]请求路径:{},异常信息:{}" , exchange . getRequest (). getPath (), ex . getMessage ());
String body ;
try {
body = objectMapper . writeValueAsString ( R . error ( BaseResultCode . ERROR , msg ));
} catch ( JsonProcessingException e ) {
throw new BaseException ( e );
}
return ServletUtil . webFluxResponseWriter ( response , body );
}
}
对网关服务进行配置安全配置,由于 Gateway 使用的是WebFlux
,所以需要使用 @EnableWebFluxSecurity
注解开启;
跨域设置
1
2
3
4
5
6
7
8
9
spring :
cloud :
gateway :
globalcors :
cors-configurations :
'[/**]' :
allowedOrigins : "https://docs.spring.io"
allowedMethods :
- GET
附录