栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

spring gateway 笔记

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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官网

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/673024.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号