网关代理转发异常

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网关代理转发异常相关的知识,希望对你有一定的参考价值。

参考技术A 通过跟踪异常信息找到对应的源码。网关是给接口做代理转发的,后端对应的是 REST API,返回数据格式是 JSON。如果不做处理,当发生异常时,Gateway 默认给出的错误信息是页面,不方便前端进行异常处理。所以需要对异常信息进行处理,并返回 JSON 格式的数据给客户。

Spring Cloud Gateway - 代理/转发 URL 的整个子部分

【中文标题】Spring Cloud Gateway - 代理/转发 URL 的整个子部分【英文标题】:Spring Cloud Gateway - Proxy/Forward the entire sub part of URL 【发布时间】:2018-07-29 15:06:35 【问题描述】:

我正在使用Spring Cloud Gateway 2.0.0.M6 测试一个简单的网关。我只想将一个 URL 转发到另一个带有 ** 正则表达式的 URL

示例 1:/integration/sbl/foo/bar => localhost:4178/a-integration/sbl/foo/bar

示例 2:/integration/sbl/baz/bad => localhost:4178/a-integration/sbl/baz/bad

到目前为止,我已经写了以下内容,但它只转发给http://localhost:4178/a-integration/

 @Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder) 
    String test = "http://localhost:4178/a-integration/";

    return builder.routes()
            .route("integration-test",
                    r -> r.path("/integration/sbl/**")
                            .uri(test)
            )
            .build();

如何修复上述代码以启用此行为?

编辑

我根据以下回复尝试了以下操作

String samtykke = "http://localhost:4178/";

return builder.routes()

        .route("samtykke", r -> r
                .path("/gb-integration/sbl/**")
                .filters(f -> f.rewritePath("/gb-integration/sbl/(?<segment>.*)", "/gb-samtykke-integration/$segment"))
                .uri(samtykke))
        .build();

我尝试了 GET http://localhost:4177/gb-integration/sbl/api/sbl/income/ 并期望返回 http://localhost:4178/gb-samtykke-integration/api/sbl/income/,但它不起作用。

输出显示:

2018-02-23 09:46:35.197 TRACE 6364 --- [ctor-http-nio-2] o.s.c.g.h.p.RoutePredicateFactory        : Pattern "/gb-integration/sbl/**" matches against value "[path='/gb-integration/sbl/api/sbl/income/']"
2018-02-23 09:46:35.198 DEBUG 6364 --- [ctor-http-nio-2] o.s.c.g.h.RoutePredicateHandlerMapping   : Route matched: samtykke
2018-02-23 09:46:35.198 DEBUG 6364 --- [ctor-http-nio-2] o.s.c.g.h.RoutePredicateHandlerMapping   : Mapping [Exchange: GET http://localhost:4177/gb-integration/sbl/api/sbl/income/] to Routeid='samtykke', uri=http://localhost:4178/, order=0, predicate=org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$245/1803714790@1d0042df, gatewayFilters=[OrderedGatewayFilterdelegate=org.springframework.cloud.gateway.filter.factory.RewritePathGatewayFilterFactory$$Lambda$247/485237151@77da026a, order=0]
2018-02-23 09:46:35.200 DEBUG 6364 --- [ctor-http-nio-2] o.s.c.g.handler.FilteringWebHandler      : Sorted gatewayFilterFactories: [OrderedGatewayFilterdelegate=GatewayFilterAdapterdelegate=org.springframework.cloud.gateway.filter.NettyWriteResponseFilter@5c534b5b, order=-1, OrderedGatewayFilterdelegate=org.springframework.cloud.gateway.filter.factory.RewritePathGatewayFilterFactory$$Lambda$247/485237151@77da026a, order=0, OrderedGatewayFilterdelegate=GatewayFilterAdapterdelegate=org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter@396639b, order=10000, OrderedGatewayFilterdelegate=GatewayFilterAdapterdelegate=org.springframework.cloud.gateway.filter.NettyRoutingFilter@a18649a, order=2147483647, OrderedGatewayFilterdelegate=GatewayFilterAdapterdelegate=org.springframework.cloud.gateway.filter.ForwardRoutingFilter@2b22a1cc, order=2147483647, OrderedGatewayFilterdelegate=GatewayFilterAdapterdelegate=org.springframework.cloud.gateway.filter.WebsocketRoutingFilter@62573c86, order=2147483647]
2018-02-23 09:46:35.232 TRACE 6364 --- [ctor-http-nio-2] o.s.c.g.filter.RouteToRequestUrlFilter   : RouteToRequestUrlFilter start
2018-02-23 09:46:35.314 TRACE 6364 --- [ctor-http-nio-1] o.s.c.g.filter.NettyWriteResponseFilter  : NettyWriteResponseFilter start

【问题讨论】:

使用重写路径设置路径过滤器 对不起,我不明白你的意思。你能用代码提供答案吗? 【参考方案1】:

您可以在路径过滤器中使用 rewritePath 功能,如此处找到的文档所指定:

https://cloud.spring.io/spring-cloud-gateway/reference/html/#rewritepath-gatewayfilter-factory

相关部分:

5.12 RewritePath GatewayFilter 工厂

RewritePath GatewayFilter Factory 采用路径正则表达式参数 和一个替换参数。这使用 Java 正则表达式 重写请求路径的灵活方式。

spring:   
  cloud:
     gateway:
       routes:
       - id: rewritepath_route
         uri: http://example.org
         predicates:
         - Path=/foo/**
         filters:
         - RewritePath=/foo/(?<segment>.*), /$\segment

对于 /foo/bar 的请求路径,这会将路径设置为 /bar 之前 发出下游请求。注意 $\ 替换为 $ 因为 YAML 规范。

在你的例子中,这看起来像:

@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder) 
    String test = "http://localhost:4178";

    return builder.routes()
            .route("integration-test", r -> r
                    .path("/integration/sbl/**")
                    .filters(f->f.rewritePath("/integration/(?<segment>.*)","/a-integration/$segment"))
                    .uri(test)
                  )
            .build();

【讨论】:

嗨。感谢您的回复。我试过这个,但它并不完全奏效。我得到以下输出: Pattern "/gb-integration/sbl/**" matches against value "[path='/gb-integration/sbl/api/sbl/income/']" RoutePredicateHandlerMapping : Route matched: samtykke o.s.c.g.h.RoutePredicateHandlerMapping : Mapping [Exchange: GET http://localhost:4177/gb-integration/sbl/api/sbl/income/] to Routeid='samtykke', uri=http://localhost:4178/, order=0 注意我稍微改变了路径。输出显示它匹配,但从调试语句看来它只重定向到localhost:4178 而不是我想要的localhost:4178/api/sbl/income。我尝试在 localhost:4177/gb-integration/sbl/api/sbl/income 上执行 GET,但我什至没有得到 localhost:4178 回来,这很奇怪,因为它从输出中看起来像是匹配了 我编辑了我的问题并在问题中添加了评论以更清楚 如果您从 URI 中删除尾部斜杠,它将起作用。 我不确定为什么云网关不只是忽略那个斜线......添加斜线会产生意外行为,我会创建一个问题【参考方案2】:

我们在这里遇到了类似的问题,虽然我同意 Boyen 的回应,但指出 “uri”参数忽略 URI 的“路径”组件可能会很有用。这在文档中并不清楚(或者至少我还没有找到),所以我希望它可以帮助其他人。

假设您要将在 /foo 收到的所有请求重定向到 http://example.org/bar

例如:/foo/x/y/z --> http://example.org/bar/x/y/z

例如,这按预期工作:

spring:   
  cloud:
     gateway:
       routes:
       - id: rewritepath_route
         uri: http://example.org
         predicates:
         - Path=/foo/**
         filters:
         - RewritePath=/foo/(?<segment>.*), /bar/$\segment

虽然这不能按预期工作(它忽略 /bar):

spring:   
  cloud:
     gateway:
       routes:
       - id: rewritepath_route
         uri: http://example.org/bar
         predicates:
         - Path=/foo/**
         filters:
         - RewritePath=/foo/(?<segment>.*), /$\segment

【讨论】:

【参考方案3】:

请在下面找到完整设置的两种配置。两种方法产生相同的结果。

设置:

网关正在http://localhost:8090 上运行 名为/context 的基本路径用作网关的入口点 一个名为my-resources 的服务在http://localhost:8091/my-resources 上运行。当/my-resources 不带参数调用时,它会返回所有资源。当使用参数调用它时,它会返回具有相应RID(如果有)的资源

网关已配置为将传输到http://localhost:8090/context/my-resources/ 的所有路径变量(可能没有)转发到uri http://localhost:8091/my-resources/

方法一:使用application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: route_id
        predicates:
        - Path=/context/my-resources/**
        filters:
        - RewritePath=/context/my-resources/(?<RID>.*), /my-resources/$\RID
        uri: http://localhost:8091

方法2:使用类似Java的配置

@Bean
public RouteLocator routes(RouteLocatorBuilder routeBuilder) 
    return routeBuilder.routes()
            .route("route_id",
                    route -> route
                            .path("/context/my-resources/**")
                            .filters(f -> f.rewritePath("/context/my-resources/(?<RID>.*)", "/my-resources/$RID"))
                            .uri("http://localhost:8091")
            )
            .build();

【讨论】:

【参考方案4】:

注意到在使用 rewritePath 时更改 contextPath 的能力似乎被 Spring Boot 2.3.X 中的更改破坏了。并且 RewritePathGatewayFilterFactory.Config 不包含用于在 Hoxton.SR7+ 中传递新 contextPath 的字段。

作为一种解决方法,我创建了一个自定义 RewritePathGatewayFilter 并使用:

ServerHttpRequest request = exchange.getRequest().mutate().contextPath(newContextPath).path(newPath).build();
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, request.getURI());
return chain.filter(exchange.mutate().request(request).build());

【讨论】:

以上是关于网关代理转发异常的主要内容,如果未能解决你的问题,请参考以下文章

Spring Cloud Gateway - 代理/转发 URL 的整个子部分

web服务器请求代理方式

Cisco配置VLAN+中继代理+NAT转发上网

本机开发时 , 网关进行转发转发的不是本机的IP地址

统一观测丨使用 Prometheus 监控 Nginx Ingress 网关最佳实践

如何修复 ZuulException:转发错误