背景
前段時間朋友咨詢他們公司某個HTTP接口偶現400錯誤,有沒有什麼好的分析方法和解決方案,使用的是Spring Cloud體系。最近有時間總結下這個問題的處理過程。
為了分析問題,筆者使用 Spring Boot 3.0.2還原報錯場景進行講解。
問題分析
從朋友回報的情況看,傳回400狀态錯誤碼的接口并不是一直出錯,出錯的機率在5%左右,得出并不是系統的錯誤,從狀态碼400來看是調用方出錯了,請求頭或者請求參數錯誤。從伺服器上查tomcat的錯誤日志,找到類似下圖的錯誤。

從錯誤日志看到,調用方的請求頭個數超過了Tomcat預設設定的個數(100個)。
定位
根據以上分析,需要在伺服器上抓包,看調用方到底使用了什麼參數。在伺服器上使用 tcpdump工具抓包分析http請求具體資訊來 定位問題。
因為不能從伺服器上下載下傳檔案,使用如下指令檢視http請求資訊。
在伺服器上檢視到類似如下的http請求資訊,通過Header資訊發送是使用的某個鍊路追蹤工具添加的鍊路調用請求資訊,每經過一次調用就會添加一個同名的Header,調用鍊路多了的話就會導緻Header個數超過Tomcat的預設值,進而導緻Tomcat抛出400錯誤。
以下是使用Postman模拟超過100個Header的請求日志資訊中的部分。
18:27:56.864393 IP 192.168.1.103.64156 > fedora.webcache: Flags [.], seq 1:1461, ack 1, win 513, length 1460: HTTP: GET / HTTP/1.1
[email protected].....'......P....=..GET / HTTP/1.1
Header0: 0
Header1: 1
Header2: 2
Header3: 3
Header4: 4
...
Header95: 95
Header96: 96
Header97: 97
Header98: 98
Header99: 99
User-Agent: PostmanRuntime/7.29.2
Accept: */*
Postman-Token: f
如果可以下載下傳檔案的話,使用下面的指令抓包,在開發機上使用wireshark工具分析http請求包資訊是最好的。
sudo tcpdump port 8080 -w http.400.cap
# 解決方案
找到問題原因之後,就好解決了。解決方案有兩種:
- 找鍊路追蹤工具的團隊解決Header的問題
- 設定Tomcat Header個數
由于不是本公司系統且需要及時解決該問題,沒辦法解決鍊路追蹤工具的問題,給朋友推薦自定義配置的方式設定Tomcat最大Header數量,代碼如下:
/**
* 自定義Tomcat配置參數
*/
@ConditionalOnProperty(value = {"server.tomcat.max-header-enable"}, havingValue = "true", matchIfMissing = false)
public class TomcatConfigure {
/**
* 最大Header數量
*/
@Value("${server.tomcat.max-header-count:100}")
private int maxHeaderCount;
@Bean
public WebServerFactoryCustomizer<ConfigurableWebServerFactory> tomcatCustomizer() {
return new WebServerFactoryCustomizer<ConfigurableWebServerFactory>() {
@Override
public void customize(ConfigurableWebServerFactory factory) {
TomcatConnectorCustomizer customizer = new TomcatConnectorCustomizer() {
@Override
public void customize(Connector connector) {
Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
protocol.setMaxHeaderCount(maxHeaderCount);
}
};
((TomcatServletWebServerFactory) factory).addConnectorCustomizers(customizer);
}
};
}
}
在應用啟動參數上加**-Dserver.tomcat.max-header-enable=true -Dserver.tomcat.max-header-count=200**,重新開機服務後解決該問題。