mirror of
https://gitee.com/dromara/RuoYi-Vue-Plus.git
synced 2026-09-20 18:15:56 +08:00
异常全局处理
This commit is contained in:
parent
08c88e9e27
commit
783a3f9946
@ -1,10 +1,12 @@
|
|||||||
package com.ruoyi.gateway.config;
|
package com.ruoyi.gateway.config;
|
||||||
|
|
||||||
|
import com.ruoyi.gateway.config.handler.GlobalErrorWebExceptionHandler;
|
||||||
import com.ruoyi.gateway.config.provider.RedisRouteDefinitionRepository;
|
import com.ruoyi.gateway.config.provider.RedisRouteDefinitionRepository;
|
||||||
import com.ruoyi.gateway.filter.CustomerGlobalFilter;
|
import com.ruoyi.gateway.filter.CustomerGlobalFilter;
|
||||||
import com.ruoyi.gateway.ratelimit.CustomerRedisRateLimiter;
|
import com.ruoyi.gateway.ratelimit.CustomerRedisRateLimiter;
|
||||||
import org.redisson.api.RedissonClient;
|
import org.redisson.api.RedissonClient;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
|
||||||
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||||
import org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter;
|
import org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter;
|
||||||
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
|
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
|
||||||
@ -53,4 +55,9 @@ public class GatewayConfig
|
|||||||
{
|
{
|
||||||
return new CustomerGlobalFilter(customerRedisRateLimiter);
|
return new CustomerGlobalFilter(customerRedisRateLimiter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ErrorWebExceptionHandler errorWebExceptionHandler() {
|
||||||
|
return new GlobalErrorWebExceptionHandler();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,76 @@
|
|||||||
|
package com.ruoyi.gateway.config.handler;
|
||||||
|
|
||||||
|
import cn.hutool.core.map.MapUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||||
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
import org.springframework.web.server.handler.ResponseStatusExceptionHandler;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网关异常通用处理器,只作用在webflux 环境下 , 优先级低于 {@link ResponseStatusExceptionHandler} 执行
|
||||||
|
* @author Wenchao Gong
|
||||||
|
* @date 2021-10-18
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Order(-1)
|
||||||
|
public class GlobalErrorWebExceptionHandler implements ErrorWebExceptionHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex)
|
||||||
|
{
|
||||||
|
ServerHttpResponse response = exchange.getResponse();
|
||||||
|
|
||||||
|
if (response.isCommitted()) {
|
||||||
|
return Mono.error(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// header set
|
||||||
|
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
if (ex instanceof ResponseStatusException) {
|
||||||
|
final ResponseStatusException statusException = (ResponseStatusException) ex;
|
||||||
|
response.setStatusCode(statusException.getStatus());
|
||||||
|
}
|
||||||
|
Optional<Integer> code = Optional.ofNullable(response.getRawStatusCode());
|
||||||
|
final String message = getMessage(ex);
|
||||||
|
|
||||||
|
return response.writeWith(Mono.fromSupplier(() -> {
|
||||||
|
DataBufferFactory bufferFactory = response.bufferFactory();
|
||||||
|
return bufferFactory.wrap(JSONUtil.toJsonStr(result(code, message))
|
||||||
|
.getBytes(StandardCharsets.UTF_8));
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getMessage(Throwable ex)
|
||||||
|
{
|
||||||
|
if(ex instanceof ResponseStatusException) {
|
||||||
|
String reason = ((ResponseStatusException) ex).getReason();
|
||||||
|
log.info(reason);
|
||||||
|
return reason;
|
||||||
|
}
|
||||||
|
String message = ex.getMessage();
|
||||||
|
log.error(message, ex);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> result(Optional<Integer> code, String message) {
|
||||||
|
final HashMap<String, Object> result = MapUtil.newHashMap(3);
|
||||||
|
result.put("code", code.orElse(HttpStatus.INTERNAL_SERVER_ERROR.value()));
|
||||||
|
result.put("message", message);
|
||||||
|
result.put("data", null);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
package com.ruoyi.gateway.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误消息常量
|
||||||
|
* @author Wenchao Gong
|
||||||
|
* @date 2021-10-18
|
||||||
|
*/
|
||||||
|
public interface ErrorMessageConstant {
|
||||||
|
String AK_REQUIRE = "没有找到授权码";
|
||||||
|
String CONTENT_TYPE_NOT_SUPPORTED = "请求ContentType不支持";
|
||||||
|
String METHOD_NOT_SUPPORTED = "请求Method不支持";
|
||||||
|
String RATE_LIMIT = "调用次数过多";
|
||||||
|
String RULE_EXPIRED = "规则已过期";
|
||||||
|
String RULE_NOT_EXIST = "规则不存在";
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
package com.ruoyi.gateway.exception;
|
package com.ruoyi.gateway.exception;
|
||||||
|
|
||||||
import lombok.NoArgsConstructor;
|
import com.ruoyi.gateway.constant.ErrorMessageConstant;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 网关异常-AK必要
|
* 网关异常-AK必要
|
||||||
@ -8,7 +8,10 @@ import lombok.NoArgsConstructor;
|
|||||||
* @author Wenchao Gong
|
* @author Wenchao Gong
|
||||||
* @date 2021-10-04
|
* @date 2021-10-04
|
||||||
*/
|
*/
|
||||||
@NoArgsConstructor
|
|
||||||
public class AkRequireException extends GatewayException {
|
public class AkRequireException extends GatewayException {
|
||||||
|
|
||||||
|
public AkRequireException()
|
||||||
|
{
|
||||||
|
super(ErrorMessageConstant.AK_REQUIRE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
package com.ruoyi.gateway.exception;
|
package com.ruoyi.gateway.exception;
|
||||||
|
|
||||||
import lombok.NoArgsConstructor;
|
import com.ruoyi.gateway.constant.ErrorMessageConstant;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 网关异常-请求方法不支持
|
* 网关异常-请求方法不支持
|
||||||
@ -8,7 +8,10 @@ import lombok.NoArgsConstructor;
|
|||||||
* @author Wenchao Gong
|
* @author Wenchao Gong
|
||||||
* @date 2021-10-04
|
* @date 2021-10-04
|
||||||
*/
|
*/
|
||||||
@NoArgsConstructor
|
|
||||||
public class ContentTypeNotSupportedException extends GatewayException {
|
public class ContentTypeNotSupportedException extends GatewayException {
|
||||||
|
|
||||||
|
public ContentTypeNotSupportedException()
|
||||||
|
{
|
||||||
|
super(ErrorMessageConstant.CONTENT_TYPE_NOT_SUPPORTED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package com.ruoyi.gateway.exception;
|
package com.ruoyi.gateway.exception;
|
||||||
|
|
||||||
import lombok.NoArgsConstructor;
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 网关异常
|
* 网关异常
|
||||||
@ -8,7 +9,30 @@ import lombok.NoArgsConstructor;
|
|||||||
* @author Wenchao Gong
|
* @author Wenchao Gong
|
||||||
* @date 2021-10-04
|
* @date 2021-10-04
|
||||||
*/
|
*/
|
||||||
@NoArgsConstructor
|
public class GatewayException extends ResponseStatusException {
|
||||||
public class GatewayException extends RuntimeException {
|
|
||||||
|
|
||||||
|
public GatewayException(String reason)
|
||||||
|
{
|
||||||
|
super(HttpStatus.INTERNAL_SERVER_ERROR, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GatewayException(HttpStatus status)
|
||||||
|
{
|
||||||
|
super(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GatewayException(HttpStatus status, String reason)
|
||||||
|
{
|
||||||
|
super(status, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GatewayException(HttpStatus status, String reason, Throwable cause)
|
||||||
|
{
|
||||||
|
super(status, reason, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GatewayException(int rawStatusCode, String reason, Throwable cause)
|
||||||
|
{
|
||||||
|
super(rawStatusCode, reason, cause);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
package com.ruoyi.gateway.exception;
|
package com.ruoyi.gateway.exception;
|
||||||
|
|
||||||
import lombok.NoArgsConstructor;
|
import com.ruoyi.gateway.constant.ErrorMessageConstant;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 网关异常-请求方法不支持
|
* 网关异常-请求方法不支持
|
||||||
@ -8,7 +8,10 @@ import lombok.NoArgsConstructor;
|
|||||||
* @author Wenchao Gong
|
* @author Wenchao Gong
|
||||||
* @date 2021-10-04
|
* @date 2021-10-04
|
||||||
*/
|
*/
|
||||||
@NoArgsConstructor
|
|
||||||
public class MethodNotSupportedException extends GatewayException {
|
public class MethodNotSupportedException extends GatewayException {
|
||||||
|
|
||||||
|
public MethodNotSupportedException()
|
||||||
|
{
|
||||||
|
super(ErrorMessageConstant.METHOD_NOT_SUPPORTED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
package com.ruoyi.gateway.exception;
|
package com.ruoyi.gateway.exception;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import com.ruoyi.gateway.constant.ErrorMessageConstant;
|
||||||
import lombok.NoArgsConstructor;
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 网关异常-限流异常
|
* 网关异常-限流异常
|
||||||
@ -11,18 +9,10 @@ import java.util.concurrent.TimeUnit;
|
|||||||
* @author Wenchao Gong
|
* @author Wenchao Gong
|
||||||
* @date 2021-10-04
|
* @date 2021-10-04
|
||||||
*/
|
*/
|
||||||
@NoArgsConstructor
|
|
||||||
public class RateLimitException extends GatewayException {
|
public class RateLimitException extends GatewayException {
|
||||||
|
|
||||||
private TimeUnit timeUnit;
|
public RateLimitException()
|
||||||
private int replenishRate;
|
{
|
||||||
private int tokensLeft;
|
super(HttpStatus.TOO_MANY_REQUESTS, ErrorMessageConstant.RATE_LIMIT);
|
||||||
private String message;
|
|
||||||
public RateLimitException(int replenishRate, int tokensLeft, TimeUnit timeUnit) {
|
|
||||||
this.replenishRate = replenishRate;
|
|
||||||
this.tokensLeft = tokensLeft;
|
|
||||||
this.timeUnit = timeUnit;
|
|
||||||
String unit = StrUtil.upperFirst(timeUnit.name().toLowerCase());
|
|
||||||
message = String.format("服务限流: 上限[%d/%s], 实际[%d/%s]", replenishRate, unit, tokensLeft, unit);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
package com.ruoyi.gateway.exception;
|
package com.ruoyi.gateway.exception;
|
||||||
|
|
||||||
import lombok.NoArgsConstructor;
|
import com.ruoyi.gateway.constant.ErrorMessageConstant;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 网关异常-规则已过期
|
* 网关异常-规则已过期
|
||||||
@ -8,7 +8,10 @@ import lombok.NoArgsConstructor;
|
|||||||
* @author Wenchao Gong
|
* @author Wenchao Gong
|
||||||
* @date 2021-10-04
|
* @date 2021-10-04
|
||||||
*/
|
*/
|
||||||
@NoArgsConstructor
|
|
||||||
public class RuleExpiredException extends GatewayException {
|
public class RuleExpiredException extends GatewayException {
|
||||||
|
|
||||||
|
public RuleExpiredException()
|
||||||
|
{
|
||||||
|
super(ErrorMessageConstant.RULE_EXPIRED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
package com.ruoyi.gateway.exception;
|
package com.ruoyi.gateway.exception;
|
||||||
|
|
||||||
import lombok.NoArgsConstructor;
|
import com.ruoyi.gateway.constant.ErrorMessageConstant;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 网关异常-规则不存在
|
* 网关异常-规则不存在
|
||||||
@ -8,7 +8,10 @@ import lombok.NoArgsConstructor;
|
|||||||
* @author Wenchao Gong
|
* @author Wenchao Gong
|
||||||
* @date 2021-10-04
|
* @date 2021-10-04
|
||||||
*/
|
*/
|
||||||
@NoArgsConstructor
|
|
||||||
public class RuleNotExistException extends GatewayException {
|
public class RuleNotExistException extends GatewayException {
|
||||||
|
|
||||||
|
public RuleNotExistException()
|
||||||
|
{
|
||||||
|
super(ErrorMessageConstant.RULE_NOT_EXIST);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,7 +16,6 @@ import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
|
|||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
import org.springframework.util.LinkedMultiValueMap;
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
@ -34,7 +33,6 @@ import java.util.function.BiConsumer;
|
|||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.setResponseStatus;
|
|
||||||
import static org.springframework.util.CollectionUtils.unmodifiableMultiValueMap;
|
import static org.springframework.util.CollectionUtils.unmodifiableMultiValueMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -310,9 +308,7 @@ public class CustomerGlobalFilter implements GlobalFilter, Ordered {
|
|||||||
}
|
}
|
||||||
return rateLimiter(exchange, rule, route, index + 1, rateLimiterAfterSupplier);
|
return rateLimiter(exchange, rule, route, index + 1, rateLimiterAfterSupplier);
|
||||||
}
|
}
|
||||||
setResponseStatus(exchange, HttpStatus.TOO_MANY_REQUESTS);
|
return Mono.error(RateLimitException::new);
|
||||||
exchange.getResponse().setComplete();
|
|
||||||
return Mono.error(new RateLimitException(limit.intValue(), 1, timeUnit));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user