【问题标题】:Spring-cloud-gateway: HTTP400 when more than 30 headers in requestSpring-cloud-gateway:请求超过 30 个标头时的 HTTP400
【发布时间】:2023-03-11 22:15:01
【问题描述】:

我使用 spring-cloud-gateway 作为 API 网关,它位于负责预身份验证(单点登录)的 apache 层后面。该层向我的 spring-cloud-gateway 应用程序的传入请求添加了一堆标头,并且当此数量超过 30 个标头时。我从网关收到 HTTP 400 响应。

我有一个自定义过滤器,它与后端用户服务对话以执行授权。此过滤器为交换请求添加更多标头。

HttpHeaders headers = new HttpHeaders();
headers.setContentType(APPLICATION_JSON);
headers.set(PRINCIPAL, userId);
HttpEntity<Void> responseType = new HttpEntity<Void>(headers);
ResponseEntity<UserDto> response = restTemplate.exchange(CURRENT_USER_ENDPOINT, HttpMethod.GET, responseType, UserDto.class);
addUserDetailsToHeaders(exchange, response.getBody());

由于某种原因,此过滤器会干扰任何具有 > 30 个标头的网关请求 当 >30 个标头时,我从网关得到的响应正文如下所示。

<html>
  <head>
    <title>Bad Request</title>
  </head>
  <body>
    <h1><p>Bad Request</p></h1>
    Error parsing headers: &#x27;limit request headers fields&#x27;
  </body>
</html>

我可以使用 curl 在本地运行我的网关时模拟该问题。例如:

curl 'http://localhost:8080/my-api-app/' -H 'Connection: keep-alive' -H 'Cache-Control: max-age=0' -H 'Upgrade-Insecure-Requests: 1' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' -H 'Sec-Fetch-Mode: navigate' -H 'Sec-Fetch-User: ?1' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3' -H 'Sec-Fetch-Site: none' -H 'Accept-Encoding: gzip, deflate, br' -H 'Accept-Language: en-GB,en;q=0.9,en-US;q=0.8,ja;q=0.7' -H 'Cookie: 567583457' -H 'uid: 1234567' -H 'employee: N' -H 'x-forwarded-proto: https' -H 'x-forwarded-for: 10.45.67.65, 172.16.8.1' -H 'X-Forwarded-Host: xxxxxxxxxxxxxxx' -H 'X-Forwarded-Server: xxxxxxxxxxxxx' -H 'Ct_request_id: 11' -H 'managername: xxxxxxxx, xxxxx'  -H 'Ctscuserkeywords: NotExpired,PasswordPolicy' -H 'Destinationindicator: IE' -H 'a: b' -H 'c: d' -H 'derek: test'  --compressed

我也可以使用 spring-cloud-gateway-sample 项目通过这个 curl 来模拟相同的 400 响应(所以真正的限制看起来像 90)

curl 'http://localhost:8080/get' -H 'key1: val' -H 'key2: val' -H 'key3: val' -H 'key4: val' -H 'key5: val' -H 'key6: val' -H 'key7: val' -H 'key8: val' -H 'key9: val' -H 'key10: val' -H 'key11: val' -H 'key12: val' -H 'key13: val' -H 'key14: val' -H 'key15: val' -H 'key16: val' -H 'key17: val' -H 'key18: val' -H 'key19: val' -H 'key20: val' -H 'key21: val' -H 'key22: val' -H 'key23: val' -H 'key24: val' -H 'key25: val' -H 'key26: val' -H 'key27: val' -H 'key28: val' -H 'key29: val' -H 'key30: val' -H 'key31: val' -H 'key32: val' -H 'key33: val' -H 'key34: val' -H 'key35: val' -H 'key36: val' -H 'key37: val' -H 'key38: val' -H 'key39: val' -H 'key40: val' -H 'key41: val' -H 'key42: val' -H 'key43: val' -H 'key44: val' -H 'key45: val' -H 'key46: val' -H 'key47: val' -H 'key48: val' -H 'key49: val' -H 'key50: val' -H 'key51: val' -H 'key52: val' -H 'key53: val' -H 'key54: val' -H 'key55: val' -H 'key56: val' -H 'key57: val' -H 'key58: val' -H 'key59: val' -H 'key60: val' -H 'key61: val' -H 'key62: val' -H 'key63: val' -H 'key64: val' -H 'key65: val' -H 'key66: val' -H 'key67: val' -H 'key68: val' -H 'key69: val' -H 'key70: val' -H 'key71: val' -H 'key72: val' -H 'key73: val' -H 'key74: val' -H 'key75: val' -H 'key76: val' -H 'key77: val' -H 'key78: val' -H 'key79: val' -H 'key80: val' -H 'key81: val' -H 'key82: val' -H 'key83: val' -H 'key84: val' -H 'key85: val' -H 'key86: val' -H 'key87: val' -H 'key88: val' -H 'key89: val' -H 'key90: val' -H 'key91: val'

【问题讨论】:

  • 我插入了 curl 命令,它对我来说很好用。你用的是什么版本?您确定错误来自网关而不是下游应用程序吗?
  • Spencer,是的,我 100% 确定它来自网关。我什至写了一个特殊的下游 python 应用程序来记录所有请求,它永远不会被命中。我确实有一些自定义过滤器。还连接了一个 Eureka 发现客户端。我正在使用 Greenwich.SR2。有趣的是,请求确实通过了我的 3 个过滤器
  • 我无法复制它。能否提供一个示例项目?
  • 斯宾塞,谢谢。原来这是我的自定义过滤器之一。我的自定义过滤器正在与另一个服务交谈以获取用户详细信息(授权),并且由于某种原因,这干扰了通过过滤器链的请求。在我的自定义过滤器中,我使用的是 Spring 的 restTemplate.exchange(....)。我认为如果我现在用更多细节更新问题会更好......在这里很难适应所有细节
  • 我更新了问题。我能够通过点击具有 > 90 个标题的 spring-cloud-sample 应用程序来重现它。我知道这是不切实际的,但我对位于我们的 PCF 实例前面的层的控制有限,它正在添加大量标题。

标签: spring-cloud spring-cloud-gateway


【解决方案1】:

问题原来是 cloudfoundry 的 cf 路由器拒绝了请求。网关没有问题。令人困惑的是cf路由器在返回400时没有添加任何响应头。

我有一个自定义过滤器,添加了一个包含逗号分隔列表的特定标题,该列表很长(200 到 300 个字符)。我减少了它的长度,然后它起作用了。

【讨论】:

  • 你怎么知道是cloudfoundry的cf路由器?
【解决方案2】:

您是否使用嵌入式 Tomcat?

查看这篇关于这个问题的文章:https://thewebspark.com/2017/12/06/tomcat-request-header-too-large-resolved/

要解决此错误,请检查发出的请求是 GET 还是 POST?

如果是 GET 请求,则将其更改为 HTTP POST,在大多数情况下,由于 URL 长度超过 2000 个字符,错误将得到解决。在这种情况下,最好使用 POST 或拆分 URL。

maxHttpHeaderSize:请求和响应 HTTP 标头的最大大小,以字节为单位。如果未指定,则此属性设置为 4096 (4 KB)。

你会发现它在

$TOMCAT_HOME/conf/server.xml

在 server.xml 中更改 HTTP/1.1 连接器条目并将 maxHttpHeaderSize 设置为“65536”(64Kb in bytes),如下所示:

连接器端口="8080" maxHttpHeaderSize="65536" 协议="HTTP/1.1" ...

如果使用嵌入式 Tomcat,请尝试对其进行配置以增加最大标头大小: https://www.baeldung.com/spring-boot-configure-tomcat

如果不使用嵌入式 Tomcat,我还在 Pivotal 的同一主题上找到了这个:https://community.pivotal.io/s/article/spring-boot-app-rejects-http-request-with-total-header-size-larger-than-8kb

【讨论】:

猜你喜欢
  • 2018-12-18
  • 1970-01-01
  • 2021-06-04
  • 2021-12-28
  • 2022-07-25
  • 2021-08-25
  • 2021-05-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多