1、API网关介绍
2、Spring Cloud Gateway
3、Spring Cloud Gateway核心概念
所有服务,都需要在nacos中注册服务
**
注意版本号
<dependencies>
<!--服务注册nacos-->
<dependency>
<groupId>org.springframework.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>
<!--服务调用-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--谷歌gson-->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<!--自己写的自定义异常的工具类 下面的统一异常如果要是用需要定义统一异常配置
可以查看统一返回异常怎样配置的-->
<dependency>
<groupId>com.yzhswj</groupId>
<artifactId>common_utils</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
server.port=8222
# 网关服务端口
server.port=8222
# 服务名
spring.application.name=service-gateway
# nacos服务地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
#使用服务发现路由
spring.cloud.gateway.discovery.locator.enabled=true
#定义规则相当于Nginx
# 0 是当前模块
#设置路由id 理论上随便写,建议用服务名
spring.cloud.gateway.routes[0].id=service-acl
#设置路由的uri lb://nacos注册服务名称
spring.cloud.gateway.routes[0].uri=lb://service-acl
#设置路由断言,匹配规则,代理servicerId为auth-service的/auth/路径
spring.cloud.gateway.routes[0].predicates= Path=/*/acl/**
#1 是 service-edu
#配置service-edu服务
spring.cloud.gateway.routes[1].id=service-edu
spring.cloud.gateway.routes[1].uri=lb://service-edu
spring.cloud.gateway.routes[1].predicates= Path=/teacher/**
#2
#3
#4
#5
#6
#.....
yml文件:
server:
port: 8222
spring:
application:
cloud:
gateway:
discovery:
locator:
enabled: true
routes:
- id: SERVICE-ACL
uri: lb://SERVICE-ACL
predicates:
- Path=/*/acl/** # 路径匹配
- id: SERVICE-EDU
uri: lb://SERVICE-EDU
predicates:
- Path=/eduservice/** # 路径匹配
- id: SERVICE-UCENTER
uri: lb://SERVICE-UCENTER
predicates:
- Path=/ucenter/** # 路径匹配
nacos:
discovery:
server-addr: 127.0.0.1:8848
4、编写启动类
@SpringBootApplication
@EnableDiscoveryClient//服务注册到nacos
public class ApiGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayApplication.class, args);
}
}
1、网关解决跨域问题
测试一下,如果有问题请使用注解的方式
配置后启动类可以不用加跨域的注解 @CrossOrigin
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedMethod("*");
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
2、全局Filter,统一处理会员登录与外部不允许访问的服务
/**
*
* 全局Filter,统一处理会员登录与外部不允许访问的服务
*
*
*
*/
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
private AntPathMatcher antPathMatcher = new AntPathMatcher();
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
//谷粒学院api接口,校验用户必须登录
if(antPathMatcher.match("/api/**/auth/**", path)) {
List<String> tokenList = request.getHeaders().get("token");
if(null == tokenList) {
ServerHttpResponse response = exchange.getResponse();
return out(response);
} else {
// Boolean isCheck = JwtUtils.checkToken(tokenList.get(0));
// if(!isCheck) {
ServerHttpResponse response = exchange.getResponse();
return out(response);
// }
}
}
//内部服务接口,不允许外部访问
if(antPathMatcher.match("/**/inner/**", path)) {
ServerHttpResponse response = exchange.getResponse();
return out(response);
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
private Mono<Void> out(ServerHttpResponse response) {
JsonObject message = new JsonObject();
message.addProperty("success", false);
message.addProperty("code", 28004);
message.addProperty("data", "鉴权失败");
byte[] bits = message.toString().getBytes(StandardCharsets.UTF_8);
DataBuffer buffer = response.bufferFactory().wrap(bits);
//response.setStatusCode(HttpStatus.UNAUTHORIZED);
//指定编码,否则在浏览器中会中文乱码
response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
return response.writeWith(Mono.just(buffer));
}
}
3、自定义异常处理
服务网关调用服务时可能会有一些异常或服务不可用,它返回错误信息不友好,需要我们覆盖处理
/**
* 覆盖默认的异常处理
*
*
*
*/
@Configuration
@EnableConfigurationProperties({ServerProperties.class, ResourceProperties.class})
public class ErrorHandlerConfig {
private final ServerProperties serverProperties;
private final ApplicationContext applicationContext;
private final ResourceProperties resourceProperties;
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public ErrorHandlerConfig(ServerProperties serverProperties,
ResourceProperties resourceProperties,
ObjectProvider<List<ViewResolver>> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer,
ApplicationContext applicationContext) {
this.serverProperties = serverProperties;
this.applicationContext = applicationContext;
this.resourceProperties = resourceProperties;
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes) {
JsonExceptionHandler exceptionHandler = new JsonExceptionHandler(
errorAttributes,
this.resourceProperties,
this.serverProperties.getError(),
this.applicationContext);
exceptionHandler.setViewResolvers(this.viewResolvers);
exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters());
exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders());
return exceptionHandler;
}
}
JsonExceptionHandler:
/**
* 自定义异常处理
*
* 异常时用JSON代替HTML异常信息
*
*
*
*/
public class JsonExceptionHandler extends DefaultErrorWebExceptionHandler {
public JsonExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties,
ErrorProperties errorProperties, ApplicationContext applicationContext) {
super(errorAttributes, resourceProperties, errorProperties, applicationContext);
}
/**
* 获取异常属性
*/
@Override
protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
Map<String, Object> map = new HashMap<>();
map.put("success", false);
map.put("code", 20005);
map.put("message", "网关失败");
map.put("data", null);
return map;
}
/**
* 指定响应处理方法为JSON处理的方法
* @param errorAttributes
*/
@Override
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
}
/**
* 根据code获取对应的HttpStatus
* @param errorAttributes
*/
@Override
protected int getHttpStatus(Map<String, Object> errorAttributes) {
return 200;
}
}