一次線上websocket返回400問題排查的實戰(zhàn)記錄
現(xiàn)象
生產(chǎn)環(huán)境websocket無法正常連接,服務(wù)端返回400 bad request,開發(fā)及測試環(huán)境均正常。

抓包排查
src:nginx服務(wù)器 172.16.177.193
dst:imp應(yīng)用服務(wù)器 172.16.177.218

問題定位
觀察到header中的host值帶有下劃線,在一些中間件(如kafka、hadoop)中,對host中的特殊字符也有限制。由此猜測是header問題。
經(jīng)排查,此header來自nginx的upstream

解決方案1
修改nginx的upstream配置,去除下劃線
解決方案2
既然upstream中用了下劃線,為何普通的http請求正常,而websocket則返回400呢?
再看正常的http請求的抓包
src: nginx服務(wù)器 172.31.47.151
dst: imp應(yīng)用服務(wù)器 172.31.47.153

可見,header中的host,被轉(zhuǎn)發(fā)到了目標(biāo)服務(wù)器,而此host并沒有下劃線,正常請求。
所以,如果不修改nginx中的upstream下劃線的配置,其實還可以在server中的websocket 對應(yīng)的location中,添加參數(shù),以便轉(zhuǎn)發(fā)原始請求的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,為何會被服務(wù)端返回400?從上述排查過程可知,應(yīng)是tomcat返回的。
這一切要從一個RFC協(xié)議規(guī)范說起
RFC-1034是一個關(guān)于DNS及域名基礎(chǔ)的標(biāo)準(zhǔn)。在「3.5 Preferred name syntax」中,有提及主機(jī)名的格式規(guī)范:由字母開頭,字母或數(shù)字結(jié)尾,中間包含字母、數(shù)字或橫桿

可見,RFC-1034標(biāo)準(zhǔn)中下劃線并不被允許。
而Tomcat在一次8.x的升級中遵循該標(biāo)準(zhǔn)對host做了此校驗,詳見鏈接
org.apache.coyote.AbstractProcessor#parseHost
org.apache.tomcat.util.http.parser.Host#parse(java.io.Reader)

總結(jié)
在我們?nèi)粘E渲胔ost參數(shù)時,都盡量避免使用下劃線。包括在/etc/hosts下進(jìn)行的配置,有時在集群環(huán)境中為了方便管理,會配置host,此時也應(yīng)注意避免使用下劃線。因為中間件可能也遵循了RTC規(guī)范。
延伸閱讀
如果大家閱讀了上述規(guī)范,可能會有疑問:為何網(wǎng)易163可以是數(shù)字開頭?大家可以先去了解下域名的解析過程。
此處科普幾個基本概念。
domain nameis the identifier of a resource in a DNS databaselabelis the part of a domain name in between dotshostnameis a special type of domain name which identifies Internet hosts
域名是在dns庫中的唯一標(biāo)識,label是域名中以「.」分隔的單元,hostname是對于一個地址的特殊域名映射。
在1989年的RFC-1101中的「3.1 Network name syntax」定義了網(wǎng)絡(luò)名詞的DNS編碼規(guī)范。允許數(shù)字開頭,只要不與十進(jìn)制八位字節(jié)形式的ip地址沖突。
在1997年的RFC-2181中「11 Name syntax」對域名語法作了澄清,下劃線不應(yīng)被DNS服務(wù)所拒絕。
而在近年的一次CA/B論壇里,眾多大廠發(fā)起投票,禁止在域名中使用下劃線,否則SSL證書將不能正常申請使用。
有興趣的朋友可以嘗試搭建一個網(wǎng)站并作域名映射??梢源_定的是,做域名映射時,因為是hostname,A和MX記錄是不能帶下劃線的。CNAME記錄由于針對的是域名,是否支持則取決于你的DNS服務(wù)商了。
到此這篇關(guān)于一次線上websocket返回400問題排查的文章就介紹到這了,更多相關(guān)websocket返回400問題內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring學(xué)習(xí)之開發(fā)環(huán)境搭建的詳細(xì)步驟
本篇文章主要介紹了Spring學(xué)習(xí)之開發(fā)環(huán)境搭建的詳細(xì)步驟,具有一定的參考價值,有興趣的可以了解一下2017-07-07
SpringBoot配置MySQL5.7與MySQL8.0的異同點詳解
MySQL 是 Java 開發(fā)中最常用的數(shù)據(jù)庫之一,而 Spring Boot 提供了便捷的配置方式,隨著 MySQL 8.0 的普及,許多開發(fā)者需要從 MySQL 5.7 升級到 8.0,在實際開發(fā)中,二者的配置方式既有相似之處,也有一些需要特別注意的不同點,所以本文給大家詳細(xì)介紹了它們的異同點2024-12-12
Java8內(nèi)存模型PermGen Metaspace實例解析
這篇文章主要介紹了Java8內(nèi)存模型PermGen Metaspace實例解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-03-03

