目录
路由定义
配置路由谓词
配置路由过滤器
自定义全局过滤器
自定义全局异常处理器
http请求超时配置
跨域配置
官方网站
执行流程
-
客户端请求进入网关
-
进入RoutePredicateHandlerMapping ,根据路由定义,创建路由对象,进行路由匹配,匹配通过往下执行,反之报错404
-
进入FilteringWebHandler ,执行过滤器链
时序图
核心类
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 Monoresolve(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 Monohttp请求超时配置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 超时: 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官网
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)