在 Spring Boot 应用程序中使用 API 网关时,HATEOAS 路径无效

Posted

技术标签:

【中文标题】在 Spring Boot 应用程序中使用 API 网关时,HATEOAS 路径无效【英文标题】:HATEOAS paths are invalid when using an API Gateway in a Spring Boot app 【发布时间】:2015-08-15 13:07:22 【问题描述】:

我有两个 Spring Boot 应用程序,其中一个用作 API 网关(如在此处讨论的 Spring Example)。连接到第一个的另一个是使用 spring-data-rest (spring-data-neo4j-rest) 公开配置文件服务。

第一个应用程序在端口 8080 上启动,并使用 zuul 将请求路由到第二个应用程序,如下所示:

zuul:
  routes:
    profiles:
      path: /profiles/**
      url: http://localhost:8083/profiles/  

这一切都很好,第二个应用程序正在处理对http://localhost:8080/profiles 的请求。但问题是响应中的 HATEOAS 链接不正确。调用第二个服务的响应是正确的:


    "_links": 
        "self": 
            "href": "http://localhost:8083/profiles?page,size,sort",
            "templated": true
        ,
        "search": 
            "href": "http://localhost:8083/profiles/search"
        
    ,
    "_embedded": 
        "profiles": [
            
                "name": "Andrew Rutter",
                "_links": 
                    "self": 
                        "href": "http://localhost:8083/profiles/0"
                    
                
            ,
            
                "name": "Andrew Rutter",
                "_links": 
                    "self": 
                        "href": "http://localhost:8083/profiles/1"
                    
                
            
        ]
    ,
    "page": 
        "size": 20,
        "totalElements": 2,
        "totalPages": 1,
        "number": 0
    

但是当这回到我的 API 网关时,链接正在被重写为


  "name": "Andrew Rutter",
  "_links": 
    "self": 
      "href": "http://localhost:8080/profiles/profiles/0"
    
  

网关路径别名加上实际的服务基 Uri。我是否错过了一个 zuul 选项来禁用该行为,只需将 hatoas uri 留在适当的位置并进行主机调整。或者有没有办法让网关后面的服务连接到 / 而不是 /profiles 的默认资源端点(在这种情况下),这样可以避免添加不需要的路径。

谢谢!

【问题讨论】:

【参考方案1】:

Zuul 或 Spring-Cloud 将“X-Forwarded-Host”标头添加到所有转发的请求中,Spring-hateoas 尊重并适当地修改链接。引用 Spring-Cloud 文档:

添加到转发请求的 X-Forwarded-Host 标头由 默认。要关闭它,请设置 zuul.addProxyHeaders = false。前缀 默认情况下会剥离路径,并且对后端的请求会拾取一个 标头“X-Forwarded-Prefix”(上面示例中的“/myusers”)。

您可以尝试推荐的修复方法,即设置zuul.addProxyHeaders=false

【讨论】:

感谢您的建议。将其设置为 false 的结果是返回的链接是指向后端服务的直接链接,这是不受欢迎的。我注意到引入的 spring-hateoas 版本是 0.16.0,因此尝试将依赖项更改为当前版本,但没有任何乐趣。我确实在网关中将 api 路径更改为 /xyz 以使事情更清楚。当我将特定配置文件请求为 /xzy/0 时,它会在内部发送到 /profiles/0,但响应中的 hateoas 链接最终会变成 /xyz/profiles/0/profiles/0【参考方案2】:

我遇到了完全相同的问题。改变你的配置如下:

zuul:
  routes:
    profiles:
      path: /profiles/**
      url: http://localhost:8083
      stripPrefix: false

这会将发送到与“/profiles/**”匹配的网关的所有请求路由到您的后端服务器“http://localhost:8083”并保留前缀(在您的情况下为“/profiles”,因为它与路由匹配)。

【讨论】:

【参考方案3】:

Zuul 转发到 /profiles contextPath。

尝试将此设置为配置:

zuul:
  routes:
    profiles:
      path: /profiles/**
      url: http://localhost:8083/

【讨论】:

谢谢,我已经尝试过了,原始请求的上下文路径没有传递给服务。在上面的示例中,我得到一个 404,表明 / 上没有任何可用的内容,因为 Spring Data Rest 公开了基于模型的端点,该模型是 /profiles/*,但网关不会自动传递它 你试过zuul: routes: profiles: path: /** url: localhost:8083/profiles 吗?【参考方案4】:

在同样的问题上挣扎了一段时间后,我终于尝试了zuul.addProxyHeaders = true,它成功了! 链接不再断开。

【讨论】:

【参考方案5】:

在我在关于 Spring Data REST 的演讲中用于 SpringOne 的演示应用程序中,我有以下配置来处理 URI 重写以及正确调整前缀标头设置。

zuul:
  routes:
    api:
      path: /api/**
      serviceId: spring-a-gram-backend
      stripPrefix: false
    files:
      path: /files/**
      serviceId: spring-a-gram-mongodb-fileservice
      stripPrefix: false

在https://github.com/gregturn/spring-a-gram/blob/master/spring-a-gram-frontend/src/main/resources/application.yml#L23-L32查看全文

【讨论】:

以上是关于在 Spring Boot 应用程序中使用 API 网关时,HATEOAS 路径无效的主要内容,如果未能解决你的问题,请参考以下文章

在Spring Boot Data JPA Rest API中使用PostgreSql时,表未找到错误

在 Spring Boot 中自动生成 API 文档 [关闭]

如何在 Spring Boot 应用程序中从 Api 网关(Zuul)调用外部服务(非 MSA)

使用 RESTful 登录 API 验证我的 Spring Boot 应用程序

CORS 策略错误 - 使用 Spring Boot + React 发现 api

Angular 应用程序和部署在 Docker 容器中的 Spring Boot API 之间的通信问题