Selaa lähdekoodia

网关替换为Spring Cloud Gateway

mrbird 6 vuotta sitten
vanhempi
commit
81be8100d0

+ 47 - 11
febs-gateway/pom.xml

@@ -1,18 +1,16 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
-
     <parent>
         <groupId>cc.mrbird</groupId>
         <artifactId>febs-cloud</artifactId>
         <version>1.0-SNAPSHOT</version>
         <relativePath>../febs-cloud/pom.xml</relativePath>
     </parent>
-
-    <artifactId>febs-gateway</artifactId>
+    <artifactId>febs-gateway-two</artifactId>
     <version>1.0-SNAPSHOT</version>
-    <name>FEBS-Gateway</name>
+    <name>FEBS-Gateway-Two</name>
     <description>FEBS-Gateway服务网关模块</description>
 
     <dependencies>
@@ -20,20 +18,59 @@
             <groupId>cc.mrbird</groupId>
             <artifactId>febs-common</artifactId>
             <version>1.0-SNAPSHOT</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-web</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>com.baomidou</groupId>
+                    <artifactId>mybatis-plus-boot-starter</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-data-redis</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.springframework.cloud</groupId>
+                    <artifactId>spring-cloud-starter-oauth2</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.springframework.cloud</groupId>
+                    <artifactId>spring-cloud-starter-security</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-gateway</artifactId>
         </dependency>
         <dependency>
             <groupId>org.springframework.cloud</groupId>
-            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
+            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-actuator</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.csp</groupId>
+            <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
+            <version>1.6.3</version>
         </dependency>
         <dependency>
             <groupId>com.alibaba.csp</groupId>
-            <artifactId>sentinel-zuul-adapter</artifactId>
+            <artifactId>sentinel-core</artifactId>
             <version>1.6.3</version>
         </dependency>
         <dependency>
-            <groupId>net.logstash.logback</groupId>
-            <artifactId>logstash-logback-encoder</artifactId>
-            <version>6.1</version>
+            <groupId>com.alibaba.csp</groupId>
+            <artifactId>sentinel-parameter-flow-control</artifactId>
+            <version>1.6.3</version>
         </dependency>
     </dependencies>
 
@@ -45,5 +82,4 @@
             </plugin>
         </plugins>
     </build>
-
 </project>

+ 0 - 4
febs-gateway/src/main/java/cc/mrbird/febs/gateway/FebsGatewayApplication.java

@@ -2,11 +2,7 @@ package cc.mrbird.febs.gateway;
 
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
-import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
 
-@EnableDiscoveryClient
-@EnableZuulProxy
 @SpringBootApplication
 public class FebsGatewayApplication {
 

+ 13 - 13
febs-gateway/src/main/java/cc/mrbird/febs/gateway/configure/FebsGateWayCorsConfigure.java

@@ -3,26 +3,26 @@ package cc.mrbird.febs.gateway.configure;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.web.cors.CorsConfiguration;
-import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
-import org.springframework.web.filter.CorsFilter;
+import org.springframework.web.cors.reactive.CorsWebFilter;
+import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
+import org.springframework.web.util.pattern.PathPatternParser;
 
 /**
- * 跨域处理
- *
  * @author MrBird
  */
 @Configuration
 public class FebsGateWayCorsConfigure {
 
     @Bean
-    public CorsFilter corsFilter() {
-        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
-        final CorsConfiguration corsConfiguration = new CorsConfiguration();
-        corsConfiguration.setAllowCredentials(true);
-        corsConfiguration.addAllowedHeader(CorsConfiguration.ALL);
-        corsConfiguration.addAllowedOrigin(CorsConfiguration.ALL);
-        corsConfiguration.addAllowedMethod(CorsConfiguration.ALL);
-        source.registerCorsConfiguration("/**", corsConfiguration);
-        return new CorsFilter(source);
+    public CorsWebFilter corsFilter() {
+        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
+        CorsConfiguration cors = new CorsConfiguration();
+        cors.setAllowCredentials(true);
+        cors.addAllowedOrigin(CorsConfiguration.ALL);
+        cors.addAllowedHeader(CorsConfiguration.ALL);
+        cors.addAllowedMethod(CorsConfiguration.ALL);
+        source.registerCorsConfiguration("/**", cors);
+        return new CorsWebFilter(source);
     }
+
 }

+ 57 - 0
febs-gateway/src/main/java/cc/mrbird/febs/gateway/configure/FebsGatewayErrorConfigure.java

@@ -0,0 +1,57 @@
+package cc.mrbird.febs.gateway.configure;
+
+import cc.mrbird.febs.gateway.handler.FebsGatewayExceptionHandler;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.boot.autoconfigure.web.ResourceProperties;
+import org.springframework.boot.autoconfigure.web.ServerProperties;
+import org.springframework.boot.web.reactive.error.ErrorAttributes;
+import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.http.codec.ServerCodecConfigurer;
+import org.springframework.web.reactive.result.view.ViewResolver;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author MrBird
+ */
+@Configuration
+public class FebsGatewayErrorConfigure {
+
+    private final ServerProperties serverProperties;
+    private final ApplicationContext applicationContext;
+    private final ResourceProperties resourceProperties;
+    private final List<ViewResolver> viewResolvers;
+    private final ServerCodecConfigurer serverCodecConfigurer;
+
+    public FebsGatewayErrorConfigure(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) {
+        FebsGatewayExceptionHandler exceptionHandler = new FebsGatewayExceptionHandler(
+                errorAttributes,
+                this.resourceProperties,
+                this.serverProperties.getError(),
+                this.applicationContext);
+        exceptionHandler.setViewResolvers(this.viewResolvers);
+        exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters());
+        exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders());
+        return exceptionHandler;
+    }
+}

+ 0 - 19
febs-gateway/src/main/java/cc/mrbird/febs/gateway/configure/FebsGatewaySecurityConfigure.java

@@ -1,19 +0,0 @@
-package cc.mrbird.febs.gateway.configure;
-
-import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
-import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
-
-/**
- * WebSecurity配置
- *
- * @author MrBird
- */
-@EnableWebSecurity
-public class FebsGatewaySecurityConfigure extends WebSecurityConfigurerAdapter {
-
-    @Override
-    protected void configure(HttpSecurity http) throws Exception {
-        http.csrf().disable().headers().frameOptions().disable();
-    }
-}

+ 24 - 24
febs-gateway/src/main/java/cc/mrbird/febs/gateway/filter/FebsGatewaySentinelFilter.java → febs-gateway/src/main/java/cc/mrbird/febs/gateway/configure/FebsGatewaySentinelConfigure.java

@@ -1,6 +1,5 @@
-package cc.mrbird.febs.gateway.filter;
+package cc.mrbird.febs.gateway.configure;
 
-import cc.mrbird.febs.gateway.fallback.FebsGatewayBlockFallbackProvider;
 import com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants;
 import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
 import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPathPredicateItem;
@@ -9,53 +8,54 @@ import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionM
 import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
 import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayParamFlowItem;
 import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
-import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.ZuulBlockFallbackManager;
-import com.alibaba.csp.sentinel.adapter.gateway.zuul.filters.SentinelZuulErrorFilter;
-import com.alibaba.csp.sentinel.adapter.gateway.zuul.filters.SentinelZuulPostFilter;
-import com.alibaba.csp.sentinel.adapter.gateway.zuul.filters.SentinelZuulPreFilter;
-import com.netflix.zuul.ZuulFilter;
-import lombok.extern.slf4j.Slf4j;
+import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
+import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.cloud.gateway.filter.GlobalFilter;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.http.codec.ServerCodecConfigurer;
+import org.springframework.web.reactive.result.view.ViewResolver;
 
 import javax.annotation.PostConstruct;
+import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 /**
- * 限流过滤器
- *
  * @author MrBird
  */
-@Slf4j
 @Configuration
-public class FebsGatewaySentinelFilter {
+public class FebsGatewaySentinelConfigure {
+    private final List<ViewResolver> viewResolvers;
+    private final ServerCodecConfigurer serverCodecConfigurer;
 
-    @Bean
-    public ZuulFilter sentinelZuulPreFilter() {
-        return new SentinelZuulPreFilter();
+    public FebsGatewaySentinelConfigure(ObjectProvider<List<ViewResolver>> viewResolversProvider,
+                                        ServerCodecConfigurer serverCodecConfigurer) {
+        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
+        this.serverCodecConfigurer = serverCodecConfigurer;
     }
 
     @Bean
-    public ZuulFilter sentinelZuulPostFilter() {
-        return new SentinelZuulPostFilter();
+    @Order(Ordered.HIGHEST_PRECEDENCE)
+    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
+        return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
     }
 
     @Bean
-    public ZuulFilter sentinelZuulErrorFilter() {
-        return new SentinelZuulErrorFilter();
+    @Order(-1)
+    public GlobalFilter sentinelGatewayFilter() {
+        return new SentinelGatewayFilter();
     }
 
     @PostConstruct
     public void doInit() {
-        ZuulBlockFallbackManager.registerProvider(new FebsGatewayBlockFallbackProvider());
         initGatewayRules();
     }
 
-    /**
-     * 定义验证码请求限流,限流规则:
-     * 60秒内同一个IP,同一个 key最多访问 10次
-     */
     private void initGatewayRules() {
         Set<ApiDefinition> definitions = new HashSet<>();
         Set<ApiPredicateItem> predicateItems = new HashSet<>();

+ 24 - 0
febs-gateway/src/main/java/cc/mrbird/febs/gateway/controller/FallbackController.java

@@ -0,0 +1,24 @@
+package cc.mrbird.febs.gateway.controller;
+
+import cc.mrbird.febs.common.entity.FebsResponse;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+import reactor.core.publisher.Mono;
+
+/**
+ * @author MrBird
+ */
+@RestController
+public class FallbackController{
+
+    @RequestMapping("fallback/{name}")
+    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+    public Mono<FebsResponse> systemFallback(@PathVariable String name) {
+        String response = String.format("访问%s超时或者服务不可用", name);
+        return Mono.just(new FebsResponse().message(response));
+    }
+
+}

+ 0 - 29
febs-gateway/src/main/java/cc/mrbird/febs/gateway/fallback/FebsGatewayBlockFallbackProvider.java

@@ -1,29 +0,0 @@
-package cc.mrbird.febs.gateway.fallback;
-
-import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.BlockResponse;
-import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.ZuulBlockFallbackProvider;
-import com.alibaba.csp.sentinel.slots.block.BlockException;
-import org.springframework.http.HttpStatus;
-
-/**
- * 自定义限流异常
- *
- * @author MrBird
- */
-public class FebsGatewayBlockFallbackProvider implements ZuulBlockFallbackProvider {
-    @Override
-    public String getRoute() {
-        return "*";
-    }
-
-    @Override
-    public BlockResponse fallbackResponse(String route, Throwable throwable) {
-        if (throwable instanceof BlockException) {
-            return new BlockResponse(HttpStatus.TOO_MANY_REQUESTS.value(),
-                    "访问频率超限", route);
-        } else {
-            return new BlockResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(),
-                    "系统内部异常", route);
-        }
-    }
-}

+ 0 - 61
febs-gateway/src/main/java/cc/mrbird/febs/gateway/filter/FebsGatewayErrorFilter.java

@@ -1,61 +0,0 @@
-package cc.mrbird.febs.gateway.filter;
-
-import cc.mrbird.febs.common.entity.FebsResponse;
-import cc.mrbird.febs.common.utils.FebsUtil;
-import com.netflix.zuul.context.RequestContext;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.cloud.netflix.zuul.filters.post.SendErrorFilter;
-import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
-import org.springframework.http.MediaType;
-import org.springframework.stereotype.Component;
-import org.springframework.util.ReflectionUtils;
-
-import javax.servlet.http.HttpServletResponse;
-
-/**
- * 处理 Zuul 异常
- *
- * @author MrBird
- */
-@Slf4j
-@Component
-public class FebsGatewayErrorFilter extends SendErrorFilter {
-
-    @Override
-    public Object run() {
-        try {
-            FebsResponse febsResponse = new FebsResponse();
-            RequestContext ctx = RequestContext.getCurrentContext();
-            String serviceId = (String) ctx.get(FilterConstants.SERVICE_ID_KEY);
-
-            ExceptionHolder exception = findZuulException(ctx.getThrowable());
-            String errorCause = exception.getErrorCause();
-            Throwable throwable = exception.getThrowable();
-            String message = throwable.getMessage();
-            message = StringUtils.isBlank(message) ? errorCause : message;
-            febsResponse = resolveExceptionMessage(message, serviceId, febsResponse);
-
-            HttpServletResponse response = ctx.getResponse();
-            FebsUtil.makeResponse(
-                    response, MediaType.APPLICATION_JSON_UTF8_VALUE,
-                    HttpServletResponse.SC_INTERNAL_SERVER_ERROR, febsResponse
-            );
-            log.error("Zull sendError:{}", febsResponse.getMessage());
-        } catch (Exception ex) {
-            log.error("Zuul sendError", ex);
-            ReflectionUtils.rethrowRuntimeException(ex);
-        }
-        return null;
-    }
-
-    private FebsResponse resolveExceptionMessage(String message, String serviceId, FebsResponse febsResponse) {
-        if (StringUtils.containsIgnoreCase(message, "time out")) {
-            return febsResponse.message("请求" + serviceId + "服务超时");
-        }
-        if (StringUtils.containsIgnoreCase(message, "forwarding error")) {
-            return febsResponse.message(serviceId + "服务不可用");
-        }
-        return febsResponse.message("Zuul请求" + serviceId + "服务异常");
-    }
-}

+ 57 - 45
febs-gateway/src/main/java/cc/mrbird/febs/gateway/filter/FebsGatewayRequestFilter.java

@@ -2,63 +2,82 @@ package cc.mrbird.febs.gateway.filter;
 
 import cc.mrbird.febs.common.entity.FebsConstant;
 import cc.mrbird.febs.common.entity.FebsResponse;
-import cc.mrbird.febs.common.utils.FebsUtil;
 import cc.mrbird.febs.gateway.properties.FebsGatewayProperties;
-import com.netflix.zuul.ZuulFilter;
-import com.netflix.zuul.context.RequestContext;
+import com.alibaba.fastjson.JSONObject;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
+import org.springframework.cloud.gateway.filter.GatewayFilterChain;
+import org.springframework.cloud.gateway.filter.GlobalFilter;
+import org.springframework.cloud.gateway.route.Route;
+import org.springframework.core.annotation.Order;
+import org.springframework.core.io.buffer.DataBuffer;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.http.server.reactive.ServerHttpResponse;
 import org.springframework.stereotype.Component;
 import org.springframework.util.AntPathMatcher;
 import org.springframework.util.Base64Utils;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
 
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
+import java.net.URI;
+import java.time.LocalDateTime;
+import java.util.LinkedHashSet;
+
+import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.*;
 
 /**
- * 请求前置过滤器
- *
  * @author MrBird
  */
 @Slf4j
 @Component
-public class FebsGatewayRequestFilter extends ZuulFilter {
+@Order(0)
+public class FebsGatewayRequestFilter implements GlobalFilter {
 
     @Autowired
     private FebsGatewayProperties properties;
-
     private AntPathMatcher pathMatcher = new AntPathMatcher();
 
     @Override
-    public String filterType() {
-        return FilterConstants.PRE_TYPE;
-    }
+    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
+        ServerHttpRequest request = exchange.getRequest();
+        ServerHttpResponse response = exchange.getResponse();
 
-    @Override
-    public int filterOrder() {
-        return 6;
-    }
+        Mono<Void> checkForbidUriResult = checkForbidUri(request, response);
+        if (checkForbidUriResult != null) {
+            return checkForbidUriResult;
+        }
 
-    @Override
-    public boolean shouldFilter() {
-        return true;
+        printLog(exchange);
+
+        byte[] token = Base64Utils.encode((FebsConstant.GATEWAY_TOKEN_VALUE).getBytes());
+        ServerHttpRequest build = request.mutate().header(FebsConstant.GATEWAY_TOKEN_HEADER, new String(token)).build();
+        ServerWebExchange newExchange = exchange.mutate().request(build).build();
+        return chain.filter(newExchange);
     }
 
-    @Override
-    public Object run() {
-        RequestContext ctx = RequestContext.getCurrentContext();
-        String serviceId = (String) ctx.get(FilterConstants.SERVICE_ID_KEY);
-        HttpServletRequest request = ctx.getRequest();
-        String host = request.getRemoteHost();
-        String method = request.getMethod();
-        String uri = request.getRequestURI();
-        log.info("请求URI:{},HTTP Method:{},请求IP:{},ServerId:{}", uri, method, host, serviceId);
+    private void printLog(ServerWebExchange exchange) {
+        URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
+        Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
+        LinkedHashSet<URI> uris = exchange.getAttribute(GATEWAY_ORIGINAL_REQUEST_URL_ATTR);
+        URI originUri = null;
+        if (uris != null) {
+            originUri = uris.stream().findFirst().orElse(null);
+        }
+        if (url != null && route != null && originUri != null) {
+            log.info("转发请求:{}://{}{} --> 目标服务:{},目标地址:{}://{}{},转发时间:{}",
+                    originUri.getScheme(), originUri.getAuthority(), originUri.getPath(),
+                    route.getId(), url.getScheme(), url.getAuthority(), url.getPath(), LocalDateTime.now()
+            );
+        }
+    }
 
+    private Mono<Void> checkForbidUri(ServerHttpRequest request, ServerHttpResponse response) {
+        String uri = request.getPath().toString();
         boolean shouldForward = true;
         String forbidRequestUri = properties.getForbidRequestUri();
         String[] forbidRequestUris = StringUtils.splitByWholeSeparatorPreserveAllTokens(forbidRequestUri, ",");
@@ -70,23 +89,16 @@ public class FebsGatewayRequestFilter extends ZuulFilter {
             }
         }
         if (!shouldForward) {
-            HttpServletResponse response = ctx.getResponse();
             FebsResponse febsResponse = new FebsResponse().message("该URI不允许外部访问");
-            try {
-                FebsUtil.makeResponse(
-                        response, MediaType.APPLICATION_JSON_UTF8_VALUE,
-                        HttpServletResponse.SC_FORBIDDEN, febsResponse
-                );
-                ctx.setSendZuulResponse(false);
-                ctx.setResponse(response);
-            } catch (IOException e) {
-                e.printStackTrace();
-            }
-            return null;
+            return makeResponse(response, febsResponse);
         }
-
-        byte[] token = Base64Utils.encode((FebsConstant.ZUUL_TOKEN_VALUE).getBytes());
-        ctx.addZuulRequestHeader(FebsConstant.ZUUL_TOKEN_HEADER, new String(token));
         return null;
     }
+
+    private Mono<Void> makeResponse(ServerHttpResponse response, FebsResponse febsResponse) {
+        response.setStatusCode(HttpStatus.FORBIDDEN);
+        response.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);
+        DataBuffer dataBuffer = response.bufferFactory().wrap(JSONObject.toJSONString(febsResponse).getBytes());
+        return response.writeWith(Mono.just(dataBuffer));
+    }
 }

+ 73 - 0
febs-gateway/src/main/java/cc/mrbird/febs/gateway/handler/FebsGatewayExceptionHandler.java

@@ -0,0 +1,73 @@
+package cc.mrbird.febs.gateway.handler;
+
+import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.boot.autoconfigure.web.ErrorProperties;
+import org.springframework.boot.autoconfigure.web.ResourceProperties;
+import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
+import org.springframework.boot.web.reactive.error.ErrorAttributes;
+import org.springframework.cloud.gateway.support.NotFoundException;
+import org.springframework.cloud.gateway.support.TimeoutException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.reactive.function.server.*;
+import org.springframework.web.server.ResponseStatusException;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author MrBird
+ */
+@Slf4j
+public class FebsGatewayExceptionHandler extends DefaultErrorWebExceptionHandler {
+
+    public FebsGatewayExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties,
+                                       ErrorProperties errorProperties, ApplicationContext applicationContext) {
+        super(errorAttributes, resourceProperties, errorProperties, applicationContext);
+    }
+
+    /**
+     * 异常处理,定义返回报文格式
+     */
+    @Override
+    protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
+        Throwable error = super.getError(request);
+        log.error(
+                "请求发生异常,请求URI:{},请求方法:{},异常信息:{}",
+                request.path(), request.methodName(), error.getMessage()
+        );
+        String errorMessage;
+        if (error instanceof NotFoundException) {
+            String serverId = StringUtils.substringAfterLast(error.getMessage(), "Unable to find instance for ");
+            serverId = StringUtils.replace(serverId, "\"", StringUtils.EMPTY);
+            errorMessage = String.format("无法找到%s服务", serverId);
+        } else if (StringUtils.containsIgnoreCase(error.getMessage(), "connection refused")) {
+            errorMessage = "目标服务拒绝连接";
+        } else if (error instanceof TimeoutException) {
+            errorMessage = "访问服务超时";
+        } else if (error instanceof ResponseStatusException
+                && StringUtils.containsIgnoreCase(error.getMessage(), HttpStatus.NOT_FOUND.toString())) {
+            errorMessage = "未找到该资源";
+        } else if (error instanceof ParamFlowException) {
+            errorMessage = "访问频率超限";
+        } else {
+            errorMessage = "网关转发异常";
+        }
+        Map<String, Object> errorAttributes = new HashMap<>(3);
+        errorAttributes.put("message", errorMessage);
+        return errorAttributes;
+    }
+
+    @Override
+    @SuppressWarnings("all")
+    protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
+        return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
+    }
+
+    @Override
+    protected HttpStatus getHttpStatus(Map<String, Object> errorAttributes) {
+        return HttpStatus.INTERNAL_SERVER_ERROR;
+    }
+}

+ 6 - 24
febs-gateway/src/main/resources/bootstrap.yml

@@ -1,28 +1,10 @@
-server:
-  port: 8301
-
 spring:
   application:
     name: FEBS-Gateway
   cloud:
-    config:
-      fail-fast: true
-      name: ${spring.application.name}
-      profile: ${spring.profiles.active}
-      discovery:
-        enabled: true
-        service-id: FEBS-Config
-  profiles:
-    active: dev
-
-eureka:
-  instance:
-    lease-renewal-interval-in-seconds: 20
-  client:
-    register-with-eureka: true
-    fetch-registry: true
-    instance-info-replication-interval-seconds: 30
-    registry-fetch-interval-seconds: 3
-    serviceUrl:
-      defaultZone: http://febs:123456@${febs-register}:8001/register/eureka/
-
+    nacos:
+      config:
+        server-addr: ${nacos.url}:8001
+        group: DEFAULT_GROUP
+        prefix: febs-gateway
+        file-extension: yaml

+ 0 - 1
febs-gateway/src/main/resources/logback-spring.xml

@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <configuration scan="true" scanPeriod="60 seconds" debug="false">
-    <contextName>febs</contextName>
     <property name="log.path" value="log/febs-gateway" />
     <property name="log.maxHistory" value="15" />
     <property name="log.colorPattern" value="%magenta(%d{yyyy-MM-dd HH:mm:ss}) %highlight(%-5level) %yellow(%thread) %green(%logger) %msg%n"/>