Gateway全局异常处理及请求响应监控

这篇具有很好参考价值的文章主要介绍了Gateway全局异常处理及请求响应监控。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

我们在上一篇文章基于压测进行Feign调优完成的服务间调用的性能调优,此时我们也关注到一个问题,如果我们统一从网关调用服务,但是网关因为某些原因报错或者没有找到服务怎么办呢?

如下所示,笔者通过网关调用account服务,但是account服务还没起来。此时请求还没有到达account就报错了,这就意味着我们服务中编写的@RestControllerAdvice对网关没有任何作用。

curl 127.0.0.1:8090/account/getByCode/zsy

响应结果如下,可以看到响应结果如下所示,要知道现如今的开发模式为前后端分离模式,前后端交互完全是基于协商好的格式,如果网关响应格式与我们规定的格式完全不一致,前端就需要特殊处理,这使得代码不仅会变得丑陋,对于后续的功能扩展的交互复杂度也会增加,而gateway默认响应错误如下:

{
    "timestamp":"2023-02-09T15:22:20.278+0000",
    "path":"/account/getByCode/zsy",
    "status":500,
    "error":"Internal Server Error",
    "message":"Connection refused: no further information: /192.168.43.73:9000"
}

gateway 如何处理后端微服务返回的json,微服务,微服务,gateway

网关异常默认处理

所以我们必须了解一下是什么原因导致网关报错会响应这个值。

我们在gateway源码中找到ErrorWebFluxAutoConfiguration这个自动装配类,可以看到下面这段代码,我们从中得知网关报错时默认使用DefaultErrorWebExceptionHandler 来返回结果,所以我们不妨看看这个类做了那些事情。

@Bean
	@ConditionalOnMissingBean(value = ErrorWebExceptionHandler.class, search = SearchStrategy.CURRENT)
	@Order(-1)
	public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes) {
	//网关默认异常处理的handler
		DefaultErrorWebExceptionHandler exceptionHandler = new DefaultErrorWebExceptionHandler(errorAttributes,
				this.resourceProperties, this.serverProperties.getError(), this.applicationContext);
		exceptionHandler.setViewResolvers(this.viewResolvers);
		exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters());
		exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders());
		return exceptionHandler;
	}

我们不妨基于debug了解一下这个类,当我们服务没有注册到nacos,并通过网关调用报错时,代码就会走到下方,route 方法第一个参数是RequestPredicate谓词,而后者则是谓词的处理,进行renderErrorViewandRoute同理将报错的请求通过renderErrorResponse返回错误结果

@Override
//route 方法第一个参数是RequestPredicate谓词,而后者则是谓词的处理,进行renderErrorView,然后通过然后通过andRoute将报错的请求通过renderErrorResponse返回错误结果
	protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
		return route(acceptsTextHtml(), this::renderErrorView).andRoute(all(), this::renderErrorResponse);
	}

我们不妨看看renderErrorResponse,可以看到一行getErrorAttributes,一旦步入我们就可以看到上文请求错误的结果格式

protected Mono<ServerResponse> renderErrorResponse(ServerRequest request) {
		boolean includeStackTrace = isIncludeStackTrace(request, MediaType.ALL);
		Map<String, Object> error = getErrorAttributes(request, includeStackTrace);
		return ServerResponse.status(getHttpStatus(error)).contentType(MediaType.APPLICATION_JSON_UTF8)
				.body(BodyInserters.fromObject(error));
	}

getErrorAttributes源码,可以看到组装的key值就是我们调试时响应的参数:

@Override
	public Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
		Map<String, Object> errorAttributes = new LinkedHashMap<>();
		errorAttributes.put("timestamp", new Date());
		errorAttributes.put("path", request.path());
		Throwable error = getError(request);
		HttpStatus errorStatus = determineHttpStatus(error);
		errorAttributes.put("status", errorStatus.value());
		errorAttributes.put("error", errorStatus.getReasonPhrase());
		errorAttributes.put("message", determineMessage(error));
		handleException(errorAttributes, determineException(error), includeStackTrace);
		return errorAttributes;
	}

自定义异常处理

了解的默认错误处理,我们就可以改造,返回一个和普通服务一样的格式给前端告知网关报错。从上文我们可知网关默认错误处理时DefaultErrorWebExceptionHandler,通过类图我们可以发现它继承了一个ErrorWebExceptionHandler,所以我们也可以继承这个类重写一个Handler

gateway 如何处理后端微服务返回的json,微服务,微服务,gateway

以笔者的代码如下,可以看到笔者使用Order注解强制获得最高异常处理优先级,然后使用bufferFactory.wrap方法传递自定义错误格式返回给前端。



@Slf4j
@Order(-1)
@Configuration
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class GlobalErrorWebExceptionHandler implements ErrorWebExceptionHandler {

    private final ObjectMapper objectMapper;

    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        ServerHttpResponse response = exchange.getResponse();
        if (response.isCommitted()) {
            return Mono.error(ex);
        }

        // 设置返回值类型为json
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);

        //设置返回编码
        if (ex instanceof ResponseStatusException) {
            response.setStatusCode(((ResponseStatusException) ex).getStatus());
        }

        return response.writeWith(Mono.fromSupplier(() -> {
            DataBufferFactory bufferFactory = response.bufferFactory();
            try {
                //writeValueAsBytes 组装错误响应结果
                return bufferFactory.wrap(objectMapper.writeValueAsBytes(ResultData.fail(500, "网关捕获到异常:" + ex.getMessage())));
            } catch (JsonProcessingException e) {
                log.error("Error writing response", ex);
                return bufferFactory.wrap(new byte[0]);
            }
        }));
    }
}

最终返回的结果如下所示,可以看到结果和一般的服务调用报错格式一模一样,这样一来前端就无需为了网关报错加一个特殊处理的逻辑了

curl 127.0.0.1:8090/account/getByCode/zsy

输出结果

{
    "status":500,
    "message":"网关捕获到异常:503 SERVICE_UNAVAILABLE \"Unable to find instance for account-service\"",
    "data":null,
    "success":false,
    "timestamp":1675959617386
}

请求响应日志监控

对于微服务架构来说,监控是很重要的,在高并发场景情况下,很多问题我们都可以在网关请求响应中定位到,所以我们希望能有这么一种方式将用户日常请求响应的日志信息记录下来,便于日常运维和性能监控。

查阅了网上的资料发现,基于MongoDB进行网关请求响应数据采集是一种不错的方案,所以笔者本篇文章整理一下笔者如何基于网关过滤器结合MongoDB完成请求日志采集。

本篇文章可能会涉及MongoDB相关的知识,不了解的读者可以参考笔者的这篇文章:

MongoDB快速入门

gateway整合MongoDB采集日志步骤

  1. 添加MongoDB依赖并完成MongoDB配置:

首先在gateway中添加MongoDB依赖,需要注意的是,笔者后续的过滤器某些代码段会用到hutool的工具类,所以这里也添加了hutool的依赖。

 <!--mongodb依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>



        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
        </dependency>

然后我们在gateway的配置中添加MongoDB的连接参数配置:

# mongodb的ip地址
spring.data.mongodb.host=ip
# mongodb端口号
spring.data.mongodb.port=27017
# mongodb数据库名称
spring.data.mongodb.database=accesslog
# 用户名
spring.data.mongodb.username=xxxx
# 密码
spring.data.mongodb.password=xxx
  1. 编写MongoDB保存逻辑:

我们希望保存网关响应的内容到mongodb中,所以我们要把我们需要的内容封装成一个对象,如下GatewayLog

@Data
public class GatewayLog {
    /**
     * 请求相对路径
     */
    private String requestPath;
    /**
     *请求方法 :get post
     */
    private String requestMethod;
    /**
     *请求协议:http rpc
     */
    private String schema;
    /**
     *请求体内容
     */
    private String requestBody;
    /**
     *响应内容
     */
    private String responseBody;
    /**
     *ip地址
     */
    private String ip;
    /**
     * 请求时间
     */
    private String requestTime;
    /**
     *响应时间
     */
    private String responseTime;
    /**
     *执行时间 单位:毫秒
     */
    private Long executeTime;

}

完成对象定义后,我们就可以编写service层接口和实现类的逻辑了:

public interface AccessLogService {

    /**
     * 保存AccessLog
     * @param gatewayLog 请求响应日志
     * @return 响应日志
     */
    GatewayLog saveAccessLog(GatewayLog gatewayLog);

}

实现类代码如下,可以看到笔者完全基于mongoTemplatesave方法将日志数据存到gatewayLog表中。

@Service
public class AccessLogServiceImpl implements AccessLogService {

    @Autowired
    private MongoTemplate mongoTemplate;

	//collection名称
    private final String collectionName="gatewayLog" ;

    @Override
    public GatewayLog saveAccessLog(GatewayLog gatewayLog) {
        GatewayLog result = mongoTemplate.save(gatewayLog, collectionName);
        return result;
    }
}
  1. 基于gateway过滤器完成请求相应日志采集,代码比较长,首先是CachedBodyOutputMessage,由于笔者用的是Spring boot 2.x版本,没有CachedBodyOutputMessage 这个类,所以笔者从网上找了一份。读者可以根据注释进行复制修改即可。
public class CachedBodyOutputMessage implements ReactiveHttpOutputMessage {
    private final DataBufferFactory bufferFactory;
    private final HttpHeaders httpHeaders;
    private Flux<DataBuffer> body = Flux.error(new IllegalStateException("The body is not set. Did handling complete with success? Is a custom \"writeHandler\" configured?"));
    private Function<Flux<DataBuffer>, Mono<Void>> writeHandler = this.initDefaultWriteHandler();

    public CachedBodyOutputMessage(ServerWebExchange exchange, HttpHeaders httpHeaders) {
        this.bufferFactory = exchange.getResponse().bufferFactory();
        this.httpHeaders = httpHeaders;
    }

    public void beforeCommit(Supplier<? extends Mono<Void>> action) {
    }

    public boolean isCommitted() {
        return false;
    }

    public HttpHeaders getHeaders() {
        return this.httpHeaders;
    }

    private Function<Flux<DataBuffer>, Mono<Void>> initDefaultWriteHandler() {
        return (body) -> {
            this.body = body.cache();
            return this.body.then();
        };
    }

    public DataBufferFactory bufferFactory() {
        return this.bufferFactory;
    }

    public Flux<DataBuffer> getBody() {
        return this.body;
    }

    public void setWriteHandler(Function<Flux<DataBuffer>, Mono<Void>> writeHandler) {
        Assert.notNull(writeHandler, "'writeHandler' is required");
        this.writeHandler = writeHandler;
    }

    public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
        return Mono.defer(() -> {
            return (Mono)this.writeHandler.apply(Flux.from(body));
        });
    }

    public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
        return this.writeWith(Flux.from(body).flatMap((p) -> {
            return p;
        }));
    }

    public Mono<Void> setComplete() {
        return this.writeWith(Flux.empty());
    }
}

过滤器代码如下,笔者将核心内容都已注释了,读者可以基于此代码进行修改


@Slf4j
@Component
public class AccessLogGlobalFilter implements GlobalFilter, Ordered {
    private final List<HttpMessageReader<?>> messageReaders = HandlerStrategies.withDefaults().messageReaders();

    //todo 存在线程安全问题,后续需要优化掉
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
    @Autowired
    private AccessLogService accessLogService;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        GatewayLog gatewayLog = new GatewayLog();

        ServerHttpRequest request = exchange.getRequest();
        //获取请求的ip,url,method,body
        String requestPath = request.getPath().pathWithinApplication().value();
        String clientIp = request.getRemoteAddress().getHostString();
        String scheme = request.getURI().getScheme();
        String method = request.getMethodValue();
        
        //数据记录到gatwayLog中
        gatewayLog.setSchema(scheme);
        gatewayLog.setRequestMethod(method);
        gatewayLog.setRequestPath(requestPath);
        gatewayLog.setRequestTime(simpleDateFormat.format(new Date().getTime()));
        gatewayLog.setIp(clientIp);

        MediaType contentType = request.getHeaders().getContentType();
        if (MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(contentType) || MediaType.APPLICATION_JSON.isCompatibleWith(contentType)) {
            return writeBodyLog(exchange, chain, gatewayLog);
        } else {
            //写入日志信息到mongoDb
            return writeBasicLog(exchange, chain, gatewayLog);
        }
    }

    private Mono<Void> writeBasicLog(ServerWebExchange exchange, GatewayFilterChain chain, GatewayLog accessLog) {
        StringBuilder builder = new StringBuilder();
        MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
        for (Map.Entry<String, List<String>> entry : queryParams.entrySet()) {
            builder.append(entry.getKey()).append("=").append(StringUtils.join(entry.getValue(), ","));
        }
        //记录响应内容
        accessLog.setRequestBody(builder.toString());

        //   获取响应体
        ServerHttpResponseDecorator decoratedResponse = recordResponseLog(exchange, accessLog);
        return chain.filter(exchange.mutate().response(decoratedResponse).build())
                .then(Mono.fromRunnable(() -> {
                    //打印日志
                    writeAccessLog(accessLog);
                }));
    }


    /**
     * 解决request body 只能读取一次问题
     *
     * @param exchange
     * @param chain
     * @param gatewayLog
     * @return
     */
    private Mono writeBodyLog(ServerWebExchange exchange, GatewayFilterChain chain, GatewayLog gatewayLog) {
        ServerRequest serverRequest = ServerRequest.create(exchange, messageReaders);
        Mono<String> modifiedBody = serverRequest.bodyToMono(String.class)
                .flatMap(body -> {
                    gatewayLog.setRequestBody(body);
                    return Mono.just(body);
                });

        // 通过 BodyInsert 插入 body(支持修改body), 避免 request body 只能获取一次
        BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class);
        HttpHeaders headers = new HttpHeaders();
        headers.putAll(exchange.getRequest().getHeaders());

        headers.remove(HttpHeaders.CONTENT_LENGTH);
        CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers);

        return bodyInserter.insert(outputMessage, new BodyInserterContext())
                .then(Mono.defer(() -> {
                    // 重新封装请求
                    ServerHttpRequest decoratedRequest = requestDecorate(exchange, headers, outputMessage);

                    // 记录响应日志
                    ServerHttpResponseDecorator decoratedResponse = recordResponseLog(exchange, gatewayLog);

                    // 记录普通的
                    return chain.filter(exchange.mutate().request(decoratedRequest).response(decoratedResponse).build())
                            .then(Mono.fromRunnable(() -> {
                                // 打印日志
                                writeAccessLog(gatewayLog);
                            }));
                }));
    }


    /**
     * 打印日志并将日志内容写入mongodb
     *
     * @param gatewayLog
     */
    private void writeAccessLog(GatewayLog gatewayLog) {
        log.info("写入网关日志,日志内容:" + JSON.toJSONString(gatewayLog));
        accessLogService.saveAccessLog(gatewayLog);
    }

    /**
     * 请求装饰器,重新计算 headers
     *
     * @param exchange
     * @param headers
     * @param outputMessage
     * @return
     */
    private ServerHttpRequestDecorator requestDecorate(ServerWebExchange exchange, HttpHeaders headers,
                                                       CachedBodyOutputMessage outputMessage) {
        return new ServerHttpRequestDecorator(exchange.getRequest()) {
            @Override
            public HttpHeaders getHeaders() {
                long contentLength = headers.getContentLength();
                HttpHeaders httpHeaders = new HttpHeaders();
                httpHeaders.putAll(super.getHeaders());
                if (contentLength > 0) {
                    httpHeaders.setContentLength(contentLength);
                } else {
                    httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
                }
                return httpHeaders;
            }

            @Override
            public Flux<DataBuffer> getBody() {
                return outputMessage.getBody();
            }
        };
    }

    /**
     * 记录响应日志
     *
     * @param exchange
     * @param gatewayLog
     * @return
     */
    private ServerHttpResponseDecorator recordResponseLog(ServerWebExchange exchange, GatewayLog gatewayLog) {
        ServerHttpResponse response = exchange.getResponse();
        DataBufferFactory bufferFactory = response.bufferFactory();

        return new ServerHttpResponseDecorator(response) {
            @SneakyThrows
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                if (body instanceof Flux) {
                    String responseTime = simpleDateFormat.format(new Date().getTime());
                    gatewayLog.setResponseTime(responseTime);
                    // 计算执行时间
                    long executeTime = (simpleDateFormat.parse(responseTime).getTime() - simpleDateFormat.parse(gatewayLog.getRequestTime()).getTime());
                    gatewayLog.setExecuteTime(executeTime);

                    // 获取响应类型,如果是 json 就打印
                    String originalResponseContentType = exchange.getAttribute(ServerWebExchangeUtils.ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR);

                    if (ObjectUtils.equals(this.getStatusCode(), HttpStatus.OK)
                            && StringUtils.isNotBlank(originalResponseContentType)
                            && originalResponseContentType.contains("application/json")) {

                        Flux<? extends DataBuffer> fluxBody = Flux.from(body);
                        return super.writeWith(fluxBody.buffer().map(dataBuffers -> {

                            // 合并多个流集合,解决返回体分段传输
                            DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
                            DataBuffer join = dataBufferFactory.join(dataBuffers);
                            byte[] content = new byte[join.readableByteCount()];
                            join.read(content);

                            // 释放掉内存
                            DataBufferUtils.release(join);
                            String responseResult = new String(content, StandardCharsets.UTF_8);
                            gatewayLog.setResponseBody(responseResult);

                            return bufferFactory.wrap(content);
                        }));
                    }
                }
                return super.writeWith(body);
            }
        };
    }

    /**
     * 调小优先级使得该过滤器最先执行
     * @return
     */
    @Override
    public int getOrder() {
        return -100;
    }
}

  1. 测试

以笔者项目为例,通过网关调用order服务:

curl 127.0.0.1:8090/order/getByCode/zsy

可以看到响应成功了,接下来我们就确认一下mongoDb中是否有存储网关请求响应信息


{"status":100,"message":"操作成功","data":{"id":1,"accountCode":"zsy","accountName":"zsy","amount":10000.00},"success":true,"timestamp":1676439102837}

通过数据库连接工具查询,可以看到网关请求响应日志也成功存储到MongoDB中。

gateway 如何处理后端微服务返回的json,微服务,微服务,gateway

参考文献

SpringCloud Alibaba微服务实战二十四 - SpringCloud Gateway的全局异常处理

软件开发设计中的上游与下游

SpringCloud Alibaba实战二十九 | SpringCloud Gateway 请求响应日志

MongoDB 数据查询操作

实战 | MongoDB的安装配置

spring cloud gateway中实现请求、响应参数日志打印文章来源地址https://www.toymoban.com/news/detail-759363.html

到了这里,关于Gateway全局异常处理及请求响应监控的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringCloud GateWay通过过滤器GatewayFilter修改请求或响应内容

    Spring Cloud Gateway在有些场景中需要获取request body内容进行参数校验或参数修改,我们通过在GatewayFilter中获取请求内容来获取和修改请求体,下面我们就基于ServerWebExchange来实现: ServerWebExchange命名为服务网络交换器,存放着重要的请求-响应属性、请求实例和响应实例等等,有

    2024年02月16日
    浏览(54)
  • SpringCloud Gateway 整合RSA对请求参数解密、响应结果加密【SpringCloud系列10】

    本文章实现的是 网关中的 参数解密、响应数据体加密功能。 1 集成 commons-codec commons-codec 是Apache开源组织提供的用于摘要运算、编码解码的包。常见的编码解码工具Base64、MD5、Hex、SHA1、DES等。 本项目中集成RSA 非对称算法,RSAUtils 工具类 然后创建一个测试类,生成一组公钥

    2024年02月06日
    浏览(43)
  • 记一次线上bug排查-----SpringCloud Gateway组件 请求头accept-encoding导致响应结果乱码

           基于公司的业务需求,在SpringCloud Gateway组件的基础上,写了一个转发服务,测试开发阶段运行正常,并实现初步使用。但三个月后,PostMan请求接口,返回异常,经排查,从日志中获取到转发响应的结果为乱码:        跟踪日志: 转发到目标接口,响应结果已乱码

    2024年02月04日
    浏览(52)
  • GateWay自定义网关全局拦截

    在com.xxxxa.gateway.filter包下创建 是在网关下面操作: 网关的包里创建: 定义方式是非常简单,只需实现 GlobalFilter 接口 —————————————————————————————————————————————— 在filter中编写自定义逻辑,可以实现下列功能: 登

    2024年02月10日
    浏览(35)
  • Gateway网关 全局过滤器

    一、全局过滤器 全局过滤器GlobalFilter 全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。 区别在于GatewayFilter通过配置定义,处理逻辑是固定的。 需求:定义全局过滤器,拦截请求,判断请求的参数是否满足下面条件: 参数中是否有au

    2024年02月07日
    浏览(50)
  • Spring Cloud GateWay 全局过滤器

    这是一个自定义的 Spring Cloud Gateway 全局过滤器(Global Filter)。在 Spring Cloud Gateway 中,全局过滤器可以在请求被路由到目标服务之前或之后执行一些操作。这个过滤器实现了 GlobalFilter 接口和 Ordered 接口,这两个接口的作用如下: GlobalFilter 接口: 这是一个 Spring Cloud Gateway 提

    2024年02月11日
    浏览(46)
  • Gateway自定义过滤器——全局过滤器

    首先,我们要知道全局过滤器其实是特殊路由过滤器(特殊的GatewayFilter),会有条件地作用于所有路由。 为什么要自定义全局过滤器?就好比是看大门的保安大叔,平时主要是做好进出大门外来人员登记即可,但是因为新冠疫情,现在还需要给外来人员测量体温等等。而已有的

    2024年02月16日
    浏览(47)
  • 基于Spring-cloud-gateway实现全局日志记录

    最近项目在线上运行出现了一些难以复现的bug需要定位相应api的日志,通过nginx提供的api请求日志难以实现,于是在gateway通过全局过滤器记录api请求日志。 接受到用户请求后,经过全局过滤器,检验是否开启相应的日志配置及相应的黑白名单配置 在gateway前置处理如记录当前

    2024年02月11日
    浏览(61)
  • 【深入解析spring cloud gateway】05 gateway请求转发实验

    三个工程: eureka-server eureka-client gateway 实验目的:通过网关访问对应的微服务:eureka-client。gateway和eureka-client注册到eureka-server上 eureka-server略 eureka-client application.yml 提供一个接口 pom.xml application.yml 定义一个filter用于去掉路径中的/gateway 自定义一个GlobalFilter,用于去掉路径

    2024年02月10日
    浏览(50)
  • Spring Cloud Gateway GlobalFilter(全局过滤器)详解(官方原版)

    GlobalFilter接口具有与GatewayFilter相同的签名。这些是有条件地应用于所有路由的特殊过滤器。 当请求与路由匹配时,过滤web处理程序会将GlobalFilter的所有实例和GatewayFilter的所有路由特定实例添加到过滤器链中。这个组合过滤器链由org.springframework.core.Ordered接口排序,您可以通

    2024年02月09日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包