使用curl指令發起websocket請求

昨日的文章沒指出websocket請求協商切換的精髓,刪除重發。


前文相關:

  • ??.NET WebSockets 核心原理初體驗[1]

  • ??SignalR 從開發到生產部署避坑指南[2]

tag:瀏覽器--->nginx--> server

其中提到nginx默認不會為客戶端轉發UpgradeConnection標頭[3], 因為為了讓被代理的后端服務器知道客戶端要升級協議,故要在nginx上顯式轉發標頭:

#?以下為?/realtime/路徑請求添加??Connection、Upgrade標頭location?/realtime/?{?????proxy_pass?http://backend;proxy_http_version?1.1;proxy_set_header?Upgrade?$http_upgrade;proxy_set_header?Connection?"upgrade";
}

事情本該就就這么簡單, 但devops總會有各種奇怪的姿勢。

小動作引起的頭腦風暴

但是運維在給nginx配置的時候,給/根路徑配置了webcoket協議升級標頭。

按照字面理解,導致所有的客戶端轉發請求都在要求切換到websocket協議,但是除了/realtime路徑, 服務器其他http路徑并沒有做websocket協議的邏輯,那其他http請求是不是都該報錯了。

e3f5a64d49423edaa657187ef96e031d.png

是實際看,所有的請求(websocket、http)都沒有報錯,都按照指定預期返回。

刨一下

利用asp.netcore默認腳手架項目:

已知http://localhost:5000/WeatherForecast是http請求,返回一大坨json數據;
WeatherForecast添加斷言日志:

24ae7e3ce044f48d0d029862fc6b2d22.png

模擬ops的錯配效果,我們給這個請求添加websocket協議升級標頭。

第一次:curl 'http://localhost:5000/WeatherForecast' -H 'Upgrade: websocket' -H 'Connection: Upgrade' --verbose?=====> 200ok、大坨json數據。

日志記錄:

該請求是不是webcocket請求:False,headers:[Accept,?*/*],?[Connection,?Upgrade],?[Host,?localhost:5000],?[User-Agent,?curl/7.79.1],?[Upgrade,?websocket]

以上說明,服務端并不認為是websocket請求,但是按照http業務處理返回了200ok+大坨json數據,這演示了ops雖然錯配,但對于常規的http請求沒造成影響。

那服務端到底是怎么認定websocket請求?

從服務端認定websocket請求的源碼[4]

0fd00fe3dee640bb2b55601f8d5e9ade.png

依次判斷;

  • ??HttpMethod: GET

  • ??Sec-WebSocket-Version標頭==13

  • ??Connection標頭==Upgrade

  • ??Upgrade標頭==websocket

  • ??有效的Sec-WebSocket-Key標頭

這樣我們就明白了,雖然websocket協議基于http,添加了httpConnectionUpgrade協商標頭,但是瀏覽器實際會給我們帶上Sec-WebSocket-Key[5]Sec-WebSocket-Version等標頭,以向服務器證明這是一個有效的websocket握手。

于是我們可以使用?curl 'http://localhost:5000/WeatherForecast' -H 'Upgrade: websocket' -H 'Connection: Upgrade' -H 'Sec-WebSocket-Version: 13' -H 'Sec-webSocket-Key: eeZn6lg/rOu8QbKwltqHDA==' --verbose?仿造客戶端websocket請求。=====> 200ok、 大坨json數據

這里提示:瀏覽器websocket會自動幫我們加上這些標頭;在前端編程 let ss = new WebSocket("ws://localhost:5000/WeatherForecast") 也會自動幫助我們帶上這些標頭。

84e984fd7c381f22ae278c459d0d697b.png
image.png

日志記錄:

該請求是不是webcocket請求:True,headers:[Accept,?*/*],?[Connection,?Upgrade],?[Host,?localhost:5000],?[User-Agent,?curl/7.79.1],?[Upgrade,?websocket],?[Sec-WebSocket-Version,?13],?[Sec-WebSocket-Key,?eeZn6lg/rOu8QbKwltqHDA==]

服務器認可這是websocket請求,服務端處理邏輯沒改,故按原http代碼邏輯返回200ok和JSON數據。

真正要讓服務端按照websocket姿勢, 要使用HttpContext.WebSockets.AcceptWebSocketAsync()告知客戶端開始切換協議,返回101響應碼[6],并在原tcp上發起全雙工通信。

協商切換

以上行為完美詮釋了協商切換?的理念。

客戶端僅攜帶 Connection、Upgrade標頭,被服務端當成一般的http標頭。

但是若帶上sec-websocket-verisonsec-websocket-key,則被認為是有效的websocket請求,既然是“協商”, 服務器依舊可以拒絕切換,用原http協議返回。

就坡下驢,將腳手架項目改成一個同時支持http和websocket協議的Action吧:

//?服務端對于websocket請求,使用服務端單向推送[HttpGet(Name?=?"GetWeatherForecast")]public?async?Task?Get(){_logger.LogInformation("該請求是不是webcocket請求:"+?HttpContext.WebSockets.IsWebSocketRequest+",headers:{0}",?Request.Headers);if?(HttpContext.WebSockets.IsWebSocketRequest){var?webSocket?=?await?HttpContext.WebSockets.AcceptWebSocketAsync();Enumerable.Range(1,?5).ToList().ForEach(async?x?=>{var?wf?=?new?WeatherForecast{Date?=?DateTime.Now.AddDays(x),TemperatureC?=?Random.Shared.Next(-20,?55),Summary?=?Summaries[Random.Shared.Next(Summaries.Length)]};var?ss?=?JsonConvert.SerializeObject(wf);var?serverMsg?=?Encoding.UTF8.GetBytes(ss);//?下面參數3:true 表示結束此次消息await?webSocket.SendAsync(new?ArraySegment<byte>(serverMsg,?0,?serverMsg.Length),?WebSocketMessageType.Text,?true,?CancellationToken.None);});}else{var?arr?=?Enumerable.Range(1,?5).Select(index?=>?new?WeatherForecast{Date?=?DateTime.Now.AddDays(index),TemperatureC?=?Random.Shared.Next(-20,?55),Summary?=?Summaries[Random.Shared.Next(Summaries.Length)]}).ToArray();await??Response.WriteAsJsonAsync(arr);}}

curl 'http://localhost:5000/WeatherForecast' -H 'Upgrade: websocket' -H 'Connection: Upgrade' -H 'Sec-WebSocket-Version: 13' -H 'Sec-webSocket-Key: eeZn6lg/rOu8QbKwltqHDA==' --verbose

4dbc9950b5ec8a0a26aa34dbf32d3121.gif

curl 'http://localhost:5000/WeatherForecast' -H 'Upgrade: websocket' -H 'Connection: Upgrade' --verbose

38f7f6427515c6f37694702c250a3824.png

回顧

  1. 1. 本文記錄了nginx在轉發websocket請求時要添加的配置。

  2. 2. 雖然ops錯配了nginx for websocket url:nginx為http請求轉發了ConnectionUpgrade標頭, 但是服務器并不認可這是websocket升級協議,僅認為是攜帶了特殊標頭的http請求,走原來的http業務處理邏輯是沒有問題的。

  3. 3. 在curl指令添加了sec-websocket-version、sec-websocket-key 標頭,從客戶端仿造了真實的websocket請求。

    再次提示:瀏覽器對websocket協商切換會自動幫我們加上這些標頭;在前端編程 let ss = new WebSocket("ws://localhost:5000/WeatherForecast") 也會自動幫助我們帶上這些標頭。
  4. 4.?websocket是基于http協議為藍本,是一個協商切換協議的行為,既然是協商, 服務端是可以拒絕協議切換,依舊采用原http協議來處理。

本文內容和制圖均為原創,文章永久更新地址請參閱左下角博客園原文;

如公號內容對您有所幫助,請一鍵三連,方便的話置一個星標 ~。。~。

引用鏈接

[1]?.NET WebSockets 核心原理初體驗:?https://www.cnblogs.com/JulianHuang/p/14681331.html
[2]?SignalR 從開發到生產部署避坑指南:?https://www.cnblogs.com/JulianHuang/p/15434137.html
[3]?nginx默認不會為客戶端轉發UpgradeConnection標頭:?https://nginx.org/en/docs/http/websocket.html
[4]?服務端認定websocket請求的源碼:?https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/WebSockets/src/WebSocketMiddleware.cs#L219
[5]?Sec-WebSocket-Key:?https://www.rfc-editor.org/rfc/rfc6455#section-11.3.1
[6]?開始切換協議,返回101響應碼:?https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/WebSockets/src/WebSocketMiddleware.cs#L134

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/283901.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/283901.shtml
英文地址,請注明出處:http://en.pswp.cn/news/283901.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Yii 2 的安裝 之 踩坑歷程

由于剛接觸yii2 ,決定先裝個試試&#xff1b;可是這一路安裝差點整吐血&#xff0c;可能還是水平有限吧&#xff0c; 但還是想把這個過程分享出來&#xff0c;讓遇到同樣問題的同學有個小小的參考&#xff0c;好了言歸正傳&#xff01;&#xff01; <(~.~)> 下面是安裝流…

設計模式之代理模式(上) 靜態代理與JDK動態代理

2019獨角獸企業重金招聘Python工程師標準>>> 代理模式 給某一個對象提供一個代理&#xff0c;并由代理對象控制對原對象的引用。靜態代理 靜態代理是由我們編寫好的類&#xff0c;在程序運行之前就已經編譯好的的類&#xff0c;此時就叫靜態代理。 說理論還是比較懵…

mysql 分頁查詢

使用limit函數 limit關鍵字的用法&#xff1a; LIMIT [offset,] rows offset指定要返回的第一行的偏移量&#xff0c;rows第二個指定返回行的最大數目。初始行的偏移量是0(不是1)。轉載于:https://www.cnblogs.com/xping/p/6703986.html

WPF 實現更換主題色

WPF 實現更換主題色WPF 使用 WPFDevelopers.Minimal 如何更換主題色作者&#xff1a;WPFDevelopersOrg原文鏈接&#xff1a; https://github.com/WPFDevelopersOrg/WPFDevelopers.Minimal框架使用大于等于.NET40&#xff1b;Visual Studio 2022;項目使用 MIT 開源許可協議&a…

vue3與vue2的區別

先來說說當下市場開發使用的問題&#xff0c;目前2021年使用vue3開發的企業還是少&#xff0c;基本上都還是以vue2的形式進行開發&#xff0c;vue3的開發模式跟react很像&#xff0c;這時候有人就會想那我學vue3有用么&#xff0c;淦&#xff0c;他喵的&#xff0c;先別激動&am…

Spring Data REST API集成Springfox、Swagger

原文: Documenting a Spring Data REST API with Springfox and Swagger 使用Spring Date REST&#xff0c;你可以迅速為Spring Date repositories的創建REST API&#xff0c;并提供CRUD和更多功能。然而&#xff0c;在嚴謹的API開發過成功&#xff0c;您還希望擁有自動生成的最…

【系統設計】S3 對象存儲

在本文中&#xff0c;我們設計了一個類似于 Amazon Simple Storage Service (S3) 的對象存儲服務。S3 是 Amazon Web Services (AWS) 提供的一項服務&#xff0c; 它通過基于 RESTful API 的接口提供對象存儲。根據亞馬遜的報告&#xff0c;到 2021 年&#xff0c;有超過 100 萬…

轉: telnet命令學習

1.每天一個linux命令&#xff08;58&#xff09;&#xff1a;telnet命令 轉自&#xff1a; http://www.cnblogs.com/peida/archive/2013/03/13/2956992.html telnet命令通常用來遠程登錄。telnet程序是基于TELNET協議的遠程登錄客戶端程序。Telnet協議是TCP/IP協議族中的一員&a…

禪道、碼云、coding、redmine、jira、teambition幾大敏捷開發項目管理系統試用對比體驗

作為一個軟件公司的管理人員&#xff0c;在項目和人員多起來后&#xff0c;就需要通過系統來對項目和人員進行管理。 我們是典型的軟件外包公司&#xff0c;專為客戶定制軟件&#xff0c;所以我們的業務都是項目型的。因此&#xff0c;在管理模式上&#xff0c;我們就要用所謂…

Dubbo中的SPI機制

Dubbo中的SPI機制 概述 Service Provider Interface 即 SPI&#xff0c;是JDK內置的一種服務提供發現機制&#xff0c;可以用來啟用框架擴展和替換組件。可以讓不同的廠商針對統一接口編寫不同的實現 SPI實際上是“接口策略模式配置文件”實現的動態加載機制。在系統設計中&…

JWT:擁有我,即擁有權力

Hi&#xff0c;這里是桑小榆。上篇文章中&#xff0c;我們一起探討了 OAuth 協議的原理以及授權認證流程&#xff0c;本次我們一起探討 jwt 令牌作為授權協議的傳輸介質。OAuth協議規范了幾個參與角色的授權標準&#xff0c;安全可控的授予第三方應用&#xff0c;第三方應用獲取…

雙十一到來之前,阿里AI設計師“魯班”1天能做4000萬張海報

相比較去年&#xff0c;“魯班”的設計技藝有所提升。 人工智能很大程度上便利了我們的生活&#xff0c;現在他們甚至還能取代了一些設計師的工作&#xff0c;在雙十一正式到來之前&#xff0c;淘寶的宣傳已經鋪天蓋地&#xff0c;然而很多人都沒想到&#xff0c;我們打開淘寶…

Appium移動自動化測試之獲取appPackage和appActivity

方法一&#xff1a;直接打開Appium,點擊左上角機器人圖標 選擇apk所在位置&#xff0c;如圖所示&#xff0c;這里以ContactManager.apk為例 方法二&#xff1a;利用dex2jar和jd-gui這兩個工具反編譯apk文件 這里仍以ContactManager.apk為例 (1)重命名ContactManager.apk為Conta…

CAD轉WPF: 關于CAD圖紙文件轉換為WPF矢量代碼文件(xaml文件)的技巧

前言&#xff1a;下面的文章&#xff0c;我將會以幾個很簡單的步驟&#xff0c;來演示一下通過CAD圖紙轉換為XAML代碼文件的方法&#xff0c;供大佬們參考。一、為了演示一個簡單的操作&#xff0c;我此處先打開一個空白的CAD&#xff0c;等下用來進行繪制點內容使用。二、自定…

python之新式類與經典類

經典類與新式類經典類:P 或 P()--深度查找&#xff0c;向上查父節點新式類 :P(object)---廣度查找&#xff0c;繼承object&#xff0c;新式類的方法較多轉載于:https://www.cnblogs.com/zyy98877/p/8574983.html

Flowportal-BPM——環境配置

環境配置&#xff1a; 一、控制面板→程序和功能→打開或不關閉Window功能→選擇選項 二、控制面板→管理工具→Internet信息服務&#xff08;IIS&#xff09;管理器→左側第一個→ISAPI和CGI限制→全部選為【允許】 三、控制面板→管理工具→Internet信息服務&#xff08;IIS&…

一篇文章帶你搞懂什么是DevOps?

DevOps DevOps 它的英文發音是 /de’v?ps/&#xff0c;類似于“迪沃普斯”&#xff0c;一詞本身是對于 development 以及 operation 兩個詞的混合&#xff0c;其目的在于縮短系統開發的生命周期&#xff0c;在這過程中發布特性、修復bug以及更新均被緊密的結合。 簡化的含義為…

iOS 時間戳的轉換

在開發iOS程序時&#xff0c;有時候需要將時間格式調整成自己希望的格式&#xff0c;這個時候我們可以用NSDateFormatter類來處理。例如&#xff1a; //實例化一個NSDateFormatter對象 NSDateFormatter *dateFormatter [[NSDateFormatter alloc] init]; //設定時間格式,這里可…

微服務架構下分布式事務解決方案 —— 阿里GTS

1 微服務的發展 微服務倡導將復雜的單體應用拆分為若干個功能簡單、松耦合的服務&#xff0c;這樣可以降低開發難度、增強擴展性、便于敏捷開發。當前被越來越多的開發者推崇&#xff0c;很多互聯網行業巨頭、開源社區等都開始了微服務的討論和實踐。Hailo有160個不同服務構成&…