使用网关异常处理类来返回给前端错误信息的json数据,可处理的类别如全局过滤器、局部过滤器中校验失败的信息。如token信息的校验,没有token时的错误信息的返回,供前端进行相应处理!
步骤:皆在网关模块操作
- 创建自定义的异常类
//自定义异常.传入对应异常信息即可
public class IllegalTokenException extends RuntimeException {
public IllegalTokenException(String message) {
super(message);
}
}
- 创建网关异常处理器
场景:在网关过滤器中,token信息未通过校验的时候
/**
* 网关全局异常处理器
* :处理网关过滤器、request、response出现问题的情况
* 不合法参数问题*/
@Configuration
public class GlobalExceptionConfiguration implements ErrorWebExceptionHandler {
//日志对象
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionConfiguration.class);
@Override //参数1: request response ex:出现异常时异常对象
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
//存放响应到response的数据
Map<String, String> result = new HashMap<>(1);
//1.获取响应对象
ServerHttpResponse response = exchange.getResponse();
//2.response是否结束 用于多个异常处理时候
if (response.isCommitted()) {
return Mono.error(ex);
}
//2.设置响应头类型
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
//3.设置响应状态吗
if (ex instanceof IllegalTokenException) {
response.setStatusCode(HttpStatus.FORBIDDEN);
} else {
response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
}
//4.设置响应内容
return response
.writeWith(Mono.fromSupplier(() -> {
DataBufferFactory bufferFactory = response.bufferFactory();
log.error("msg:",ex);
result.put("msg", ex.getMessage());
ObjectMapper objectMapper = new ObjectMapper();
try {
//设置响应到response的数据
return bufferFactory.wrap(objectMapper.writeValueAsBytes(result));
} catch (JsonProcessingException e) {
e.printStackTrace();
return null;
}
}));
}
}
- 在局部、全局过滤器中对相关不合法或异常情况进行手动抛出即可
/**
* GateWay网关的局部过滤器
* 检验请求有无参数name
* */
@Component
public class MyParamGatewayFilterFactory extends AbstractGatewayFilterFactory<MyParamGatewayFilterFactory.Config> {
/**使用日志纪记录相关信息*/
private final static Logger log = LoggerFactory.getLogger(MyParamGatewayFilterFactory.class);
public MyParamGatewayFilterFactory() {
super(Config.class);
}
/**
* 绑定Config类的参数的值为yaml中配置的值*/
@Override
public List<String> shortcutFieldOrder() {
//指定把yaml配置的过滤器的值赋值给配置类的param属性。 - MyParam=name即param=name
//如果Config中定义了多个属性时候传入即可。例如声明了config中有name和age 配置文件中为- MyParam=name,age
//return Arrays.asList("param","age");
return Arrays.asList("param");
}
/**
* 过滤相关操作,定义自己的过滤逻辑。Config为配置类传来的yaml配置类中配置的局部过滤器的的参数的值*/
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
log.info("进入过滤器");
// http://localhost:9090/admins/demos?name=yh 相当于config.param ==> name
//获取请求参数中param对应的参数名 的参数值
ServerHttpRequest request = exchange.getRequest();
if (request.getQueryParams().containsKey(config.param)){//此处循环遍历是因为可以为一个参数名称指定多个值。如name=yh&name=zq
//一般一个属性只给传一个值
//String value=request.getQueryParams().get(config.param).get(0);
request.getQueryParams().get(config.param).forEach((v) -> {
log.info("获得请求的参数::"+config.param+"="+ v);
//做相应的业务处理
});
}
else {
throw new IllegalTokenException("no params name!");
}
return chain.filter(exchange);//执行请求
};
}
/**
* 自定义配置类
* 用于接收yaml中过滤器配置的参数。 - MyParam=name 即param=name.在shortcutFieldOrder方法中进行绑定*/
public static class Config{
//对应配置在application.yml配置文件中的过滤器参数名
private String param;
public String getParam() {
return param;
}
public void setParam(String param) {
this.param = param;
}
}
}
- 配置局部过滤器
在网关配置文件的filters下添加即可
server:
port: 9090
spring:
# application:
# name: API-GATEWAY
cloud:
# nacos:
# server-addr: 8.142.68.138:8848
gateway:
routes: #配置路由规则
# admins
- id: admins_router
# 配置路由到的地址ip:port
uri: lb://API-ADMINS
# 配置路径的映射
predicates:
- Path=/admins/**
filters:
# 去除断言前的路径.1代表去除一级
- StripPrefix=1
#局部过滤器名字的前部分
- MyParam=name
- 使用网关访问配置了局部过滤器的请求,没有name参数会报错
这样可以很好的向前端返回数据而不是404
完结撒花