我正在使用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: 'limit request headers fields'
</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 项目模拟相同的 400 响应,方法是用这个 curl 击中它(所以实际限制看起来像 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'
问题原来是Cloudfoundry的cf路由器拒绝了请求。网关没有问题。令人困惑的是,cf 路由器在返回 400 时不会添加任何响应标头。
我有一个自定义过滤器,添加一个包含逗号分隔列表的特定标题,该列表很长(200 到 300 个字符(。我缩短了这个的长度,然后它起作用了。
你使用的是嵌入式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
在服务器中.xml更改 HTTP/1.1 连接器条目并将 maxHttpHeaderSize 设置为"65536"(64Kb 字节(,如下所示:
连接器端口="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