Forráskód Böngészése

fix 修复 gateway sentinel 限流报错问题(临时方案) https://github.com/alibaba/Sentinel/issues/3298

疯狂的狮子Li 2 éve
szülő
commit
6186fdaeda

+ 95 - 0
ruoyi-gateway/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/sc/callback/DefaultBlockRequestHandler.java

@@ -0,0 +1,95 @@
+/*
+ * Copyright 1999-2019 Alibaba Group Holding Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.csp.sentinel.adapter.gateway.sc.callback;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.http.InvalidMediaTypeException;
+import org.springframework.http.MediaType;
+import org.springframework.web.reactive.function.server.ServerResponse;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+import java.util.List;
+
+import static org.springframework.web.reactive.function.BodyInserters.fromObject;
+
+// https://github.com/alibaba/Sentinel/issues/3298
+// 临时解决 sentinel 限流插件 jdk17 报错问题
+/**
+ * The default implementation of {@link BlockRequestHandler}.
+ * Compatible with Spring WebFlux and Spring Cloud Gateway.
+ *
+ * @author Eric Zhao
+ */
+public class DefaultBlockRequestHandler implements BlockRequestHandler {
+
+    private static final String DEFAULT_BLOCK_MSG_PREFIX = "Blocked by Sentinel: ";
+
+    @Override
+    public Mono<ServerResponse> handleRequest(ServerWebExchange exchange, Throwable ex) {
+        if (acceptsHtml(exchange)) {
+            return htmlErrorResponse(ex);
+        }
+        // JSON result by default.
+        return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS)
+            .contentType(MediaType.APPLICATION_JSON_UTF8)
+            .body(fromObject(buildErrorResult(ex)));
+    }
+
+    private Mono<ServerResponse> htmlErrorResponse(Throwable ex) {
+        return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS)
+            .contentType(MediaType.TEXT_PLAIN)
+            .syncBody(DEFAULT_BLOCK_MSG_PREFIX + ex.getClass().getSimpleName());
+    }
+
+    private ErrorResult buildErrorResult(Throwable ex) {
+        return new ErrorResult(HttpStatus.TOO_MANY_REQUESTS.value(),
+            DEFAULT_BLOCK_MSG_PREFIX + ex.getClass().getSimpleName());
+    }
+
+    /**
+     * Reference from {@code DefaultErrorWebExceptionHandler} of Spring Boot.
+     */
+    private boolean acceptsHtml(ServerWebExchange exchange) {
+        try {
+            List<MediaType> acceptedMediaTypes = exchange.getRequest().getHeaders().getAccept();
+            acceptedMediaTypes.remove(MediaType.ALL);
+            MediaType.sortBySpecificityAndQuality(acceptedMediaTypes);
+            return acceptedMediaTypes.stream()
+                .anyMatch(MediaType.TEXT_HTML::isCompatibleWith);
+        } catch (InvalidMediaTypeException ex) {
+            return false;
+        }
+    }
+
+    private static class ErrorResult {
+        private final int code;
+        private final String message;
+
+        ErrorResult(int code, String message) {
+            this.code = code;
+            this.message = message;
+        }
+
+        public int getCode() {
+            return code;
+        }
+
+        public String getMessage() {
+            return message;
+        }
+    }
+}