記一次線上websocket返回400問題排查

CLAYJJ發表於2022-04-09

現象

生產環境websocket無法正常連線,服務端返回400 bad request,開發及測試環境均正常。

 

 

 

 

 

 

抓包排查

src:nginx伺服器 172.16.177.193
dst:imp應用伺服器 172.16.177.218

 

問題定位

觀察到header中的host值帶有下劃線,在一些中介軟體(如kafka、hadoop)中,對host中的特殊字元也有限制。由此猜測是header問題。
經排查,此header來自nginx的upstream

 

 

 

解決方案1

修改nginx的upstream配置,去除下劃線

解決方案2

既然upstream中用了下劃線,為何普通的http請求正常,而websocket則返回400呢?

再看正常的http請求的抓包

src: nginx伺服器 172.31.47.151
dst: imp應用伺服器 172.31.47.153

 

 

可見,header中的host,被轉發到了目標伺服器,而此host並沒有下劃線,正常請求。
所以,如果不修改nginx中的upstream下劃線的配置,其實還可以在server中的websocket 對應的location中,新增引數,以便轉發原始請求的host

proxy_set_header Host $host;
proxy_set_header X-real-ip $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;


 

 

配置後的抓包如下

 

 

請求正常

 

原因探討

帶有下劃線的host,為何會被服務端返回400?從上述排查過程可知,應是tomcat返回的。
這一切要從一個RFC協議規範說起
RFC-1034 是一個關於DNS及域名基礎的標準。在「3.5 Preferred name syntax」中,有提及主機名的格式規範:由字母開頭,字母或數字結尾,中間包含字母、數字或橫杆

 

 

可見,RFC-1034標準中下劃線並不被允許。

而Tomcat在一次8.x的升級中遵循該標準對host做了此校驗,詳見連結
org.apache.coyote.AbstractProcessor#parseHost
org.apache.tomcat.util.http.parser.Host#parse(java.io.Reader)

 

 

總結

在我們日常配置host引數時,都儘量避免使用下劃線。包括在/etc/hosts下進行的配置,有時在叢集環境中為了方便管理,會配置host,此時也應注意避免使用下劃線。因為中介軟體可能也遵循了RTC規範。

延伸閱讀

如果大家閱讀了上述規範,可能會有疑問:為何網易163可以是數字開頭?大家可以先去了解下域名的解析過程。
此處科普幾個基本概念。

  • domain name is the identifier of a resource in a DNS database
  • label is the part of a domain name in between dots
  • hostname is a special type of domain name which identifies Internet hosts

域名是在dns庫中的唯一標識,label是域名中以「.」分隔的單元,hostname是對於一個地址的特殊域名對映。

在1989年的RFC-1101中的「3.1 Network name syntax」定義了網路名詞的DNS編碼規範。允許數字開頭,只要不與十進位制八位位元組形式的ip地址衝突。
在1997年的RFC-2181中「11 Name syntax」對域名語法作了澄清,下劃線不應被DNS服務所拒絕。
而在近年的一次CA/B論壇裡,眾多大廠發起投票,禁止在域名中使用下劃線,否則SSL證照將不能正常申請使用。

有興趣的朋友可以嘗試搭建一個網站並作域名對映。可以確定的是,做域名對映時,因為是hostname,A和MX記錄是不能帶下劃線的。CNAME記錄由於針對的是域名,是否支援則取決於你的DNS服務商了。

相關文章