天天看點

Spring Boot HTTP 400排查背景問題分析定位

背景

前段時間朋友咨詢他們公司某個HTTP接口偶現400錯誤,有沒有什麼好的分析方法和解決方案,使用的是Spring Cloud體系。最近有時間總結下這個問題的處理過程。

為了分析問題,筆者使用 Spring Boot 3.0.2還原報錯場景進行講解。

問題分析

從朋友回報的情況看,傳回400狀态錯誤碼的接口并不是一直出錯,出錯的機率在5%左右,得出并不是系統的錯誤,從狀态碼400來看是調用方出錯了,請求頭或者請求參數錯誤。從伺服器上查tomcat的錯誤日志,找到類似下圖的錯誤。

Spring Boot HTTP 400排查背景問題分析定位

從錯誤日志看到,調用方的請求頭個數超過了Tomcat預設設定的個數(100個)。

定位

根據以上分析,需要在伺服器上抓包,看調用方到底使用了什麼參數。在伺服器上使用 tcpdump工具抓包分析http請求具體資訊來 定位問題。

因為不能從伺服器上下載下傳檔案,使用如下指令檢視http請求資訊。

在伺服器上檢視到類似如下的http請求資訊,通過Header資訊發送是使用的某個鍊路追蹤工具添加的鍊路調用請求資訊,每經過一次調用就會添加一個同名的Header,調用鍊路多了的話就會導緻Header個數超過Tomcat的預設值,進而導緻Tomcat抛出400錯誤。

以下是使用Postman模拟超過100個Header的請求日志資訊中的部分。

Spring Boot HTTP 400排查背景問題分析定位
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
           
Spring Boot HTTP 400排查背景問題分析定位

# 解決方案

找到問題原因之後,就好解決了。解決方案有兩種:

  • 找鍊路追蹤工具的團隊解決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**,重新開機服務後解決該問題。

繼續閱讀