spring gateway 笔记

spring gateway 笔记,第1张

spring gateway 笔记

 

目录

路由定义

配置路由谓词

配置路由过滤器

自定义全局过滤器

自定义全局异常处理器

http请求超时配置

跨域配置

官方网站


执行流程

  1. 客户端请求进入网关

  2. 进入RoutePredicateHandlerMapping ,根据路由定义,创建路由对象,进行路由匹配,匹配通过往下执行,反之报错404

  3. 进入FilteringWebHandler ,执行过滤器链

时序图

核心类

class类作用RoutePredicateHandlerMapping路由转发RouteDefinitionRouteLocator根据路由定义,创建路由对象FilteringWebHandler合并全局过滤器、默认过滤器、路由配置过滤器,排序,执行过滤器链GatewayFilterFactory创建过滤器RoutePredicateFactory创建谓词DefaultGatewayFilterChain执行过滤器链

路由定义

public class Route implements Ordered {
    
    // 路由唯一标志,
    private final String id;
    
    // 路由转发对应微服务的地址
    private final URI uri;
    
    // 路由执行顺序编号
    private final int order;
    
    //谓词
    private final AsyncPredicate predicate;
    
    //网关过滤器集合
    private final List gatewayFilters;
    
    //省略部分源代码
}

配置路由谓词

路径路由谓词工厂(PathRoutePredicateFactory)

支持配置多个路径

  • 简写方式

spring:
  cloud:
    gateway:
      routes:
      # '-'代表一个对象
      - id: path_route
        uri: lb://product-service
        predicates:
        #简写
        - Path=/a/get/{segment} # 如果请求路径为/a/get//1或/a/get/bar,则此路由匹配。多个谓词,以‘,’分隔开
  • 完整写法

spring:
  cloud:
    gateway:
      routes:
      - id: path_route
        uri: lb://product-service
        predicates:
         - name: Path # 路由谓词工厂的前缀,如PathRoutePredicateFactory
           args: # args 下的参数,需要根据每个谓词工厂中的Config内部类的属性定义。
            patterns: /a
@Component
@Slf4j
public class MyKeyResolver implements KeyResolver {
​
    @Override
    public Mono resolve(ServerWebExchange exchange) {
        String hostAddress = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
        log.info("hostAddress:{}",hostAddress);
        return Mono.just(hostAddress);
    }
}

HystrixGatewayFilterFactory

熔断降级过滤器。

spring:
  cloud:
    gateway:
      routes:
      - id: path_route
        uri: lb://product-service
        predicates:
         - Path=/a
@RestController
@Slf4j
public class FallbackController {
​
    @RequestMapping("fallback")
    @ResponseStatus
    public String fallback(ServerWebExchange exchange) throws Exception {
        Exception exception = exchange.getAttribute(ServerWebExchangeUtils.HYSTRIX_EXECUTION_EXCEPTION_ATTR);
        ServerWebExchange delegate = ((ServerWebExchangeDecorator) exchange).getDelegate();
        log.error("接口调用失败,URL={}", delegate.getRequest().getURI(), exception);
        if (exception instanceof HystrixTimeoutException) {
            log.error("msg {}", "接口调用超时");
            throw new BizException("100","接口调用超时");
        } else if (exception != null && exception.getMessage() != null) {
            log.error("msg {}", "接口调用失败: " + exception.getMessage());
            throw new BizException("100","接口调用失败,失败原因:"+exception.getMessage());
        } else {
            log.error("msg {}", "接口调用失败");
            throw new BizException("100","接口调用失败:"+exception.getMessage());
        }
    }
}

接口调用,出现降级,执行下面方法

    @Override
        protected Observable resumeWithFallback() {
            
            //没有配置降级接口,调用父类降级处理
            if (this.fallbackUri == null) {
                return super.resumeWithFallback();
            }
​
            // TODO: copied from RouteToRequestUrlFilter
            URI uri = exchange.getRequest().getURI();
            // TODO: assume always?
            boolean encoded = containsEncodedParts(uri);
            URI requestUrl = UriComponentsBuilder.fromUri(uri).host(null).port(null)
                    .uri(this.fallbackUri).scheme(null).build(encoded).toUri();
            //保存降级地址
            exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
            addExceptionDetails();
            //重新构造request,请求降级接口
            ServerHttpRequest request = this.exchange.getRequest().mutate()
                    .uri(requestUrl).build();
            ServerWebExchange mutated = exchange.mutate().request(request).build();
            return RxReactiveStreams.toObservable(getDispatcherHandler().handle(mutated));
        }
    }

自定义全局过滤器

自定义全局过滤器,可以做身份验证等一些安全功能。每个请求都会经过。

@Slf4j
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //鉴权
        List name = exchange.getRequest().getHeaders().get("name");
        log.info("name:{}",name);
        String path = exchange.getRequest().getURI().getPath();
        //path:/a/helloword
        log.info("path:{}",path);
        String url = exchange.getRequest().getURI().toString();
        //url:http://localhost:8082/a/helloword
        log.info("url:{}",url);
        if (CollectionUtils.isEmpty(name)) {
            return Mono.error(new BizException("100","当前未登录"));
        }
        return chain.filter(exchange);
    }
​
    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
}

自定义全局异常处理器
@Component
@Order(-1)
@Slf4j
public class GlobalExceptionHandler implements WebExceptionHandler {
​
    @Override
    public Mono handle(ServerWebExchange exchange, Throwable ex) {
​
        //获取原始请求地址
        linkedHashSet uris = exchange
                .getAttribute(ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR);
        String url;
        if (CollectionUtils.isEmpty(uris)) {
            url = exchange.getRequest().getURI().toString();
        } else {
            url = uris.stream().findFirst().get().toString();
        }
        log.error("url:{},调用失败:",url,ex);
        R r = null;
        if (ex instanceof TimeoutException) {
            r = R.error("接口调用超时,请稍后重试");
        } else if (ex instanceof BizException) {
            BizException e = (BizException) ex;
            r = R.error(e.getMessage());
        } else if (ex instanceof ResponseStatusException) {
            ResponseStatusException e = (ResponseStatusException) ex;
            if (e.getStatus().is4xxClientError()) {
                r = R.error("服务不存在,请联系管理员");
            } else if (e.getStatus().is5xxServerError()) {
                r = R.error("系统异常,请联系管理员");
            }
        }else {
            r = R.error("接口调用失败,请稍后重试");
        }
        String responseStr = JSONObject.toJSonString(r);
        ServerHttpResponse response = exchange.getResponse();
        //处理响应乱码
        response.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);
        return response.writeWith(Mono.fromSupplier(() -> {
            DataBufferFactory factory = response.bufferFactory();
            try {
                return factory.wrap(responseStr.getBytes("UTF-8"));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                return factory.wrap(new byte[0]);
            }
        }));
    }
}

http请求超时配置

全局超时

配置全局 http 超时: connect-timeout必须以毫秒为单位指定。 response-timeout必须指定为 java.time.Duration

spring:
  cloud:
    gateway:
      httpclient:
        connect-timeout: 1000
        response-timeout: 5s

每个路由超时

要配置每条路由超时: connect-timeout必须以毫秒为单位指定。 response-timeout必须以毫秒为单位指定。

      - id: per_route_timeouts
        uri: https://example.org
        predicates:
          - name: Path
            args:
              pattern: /delay/{timeout}
        metadata:
          response-timeout: 200
          connect-timeout: 200

跨域配置
spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
             # 允许携带认证信息
          # 允许跨域的源(网站域名/ip),设置*为全部
          # 允许跨域请求里的head字段,设置*为全部
          # 允许跨域的method, 默认为GET和OPTIONS,设置*为全部
          # 跨域允许的有效期
            allow-credentials: true
            allowedOrigins: "*"
            allowedHeaders: "*"
            allowedMethods: "*"

参考GlobalCorsProperties 配置

官方网站

参考spring官网

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5678246.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存