使用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-Keyhttps://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.mzph.cn/news/283901.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Yii 2 的安装 之 踩坑历程

由于刚接触yii2 ,决定先装个试试&#xff1b;可是这一路安装差点整吐血&#xff0c;可能还是水平有限吧&#xff0c; 但还是想把这个过程分享出来&#xff0c;让遇到同样问题的同学有个小小的参考&#xff0c;好了言归正传&#xff01;&#xff01; <(~.~)> 下面是安装流…

设计模式之代理模式(上) 静态代理与JDK动态代理

2019独角兽企业重金招聘Python工程师标准>>> 代理模式 给某一个对象提供一个代理&#xff0c;并由代理对象控制对原对象的引用。静态代理 静态代理是由我们编写好的类&#xff0c;在程序运行之前就已经编译好的的类&#xff0c;此时就叫静态代理。 说理论还是比较懵…

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以及更新均被紧密的结合。 简化的含义为…

微服务架构下分布式事务解决方案 —— 阿里GTS

1 微服务的发展 微服务倡导将复杂的单体应用拆分为若干个功能简单、松耦合的服务&#xff0c;这样可以降低开发难度、增强扩展性、便于敏捷开发。当前被越来越多的开发者推崇&#xff0c;很多互联网行业巨头、开源社区等都开始了微服务的讨论和实践。Hailo有160个不同服务构成&…

重要消息丨.NET Core 3.1 将于今年12月13日结束支持

点击上方蓝字关注我们&#xff08;本文阅读时间&#xff1a;5分钟).NET Core 3.1 将于 2022 年 12 月 13 日结束支持。此后&#xff0c;Microsoft 将不再为 .NET Core 3.1 提供服务更新或技术支持。我们建议尽快迁移到 .NET 6。如果您在支持日期结束后仍在使用 .NET Core 3.1&a…

产品设计的三大原则

1.它有用吗? 如果我们必须从这三个特性中选择一个作为最重要的&#xff0c;那就是有用性。 首要的是&#xff0c;一个产品必须有用。如果它无用&#xff0c;其它任何东西都是不相关的&#xff0c;因为没有人会需要它。很明显&#xff0c;有用性和可享用性看上去一样重要&#…

常用的17个运维监控系统

1. Zabbix Zabbix 作为企业级的网络监控工具&#xff0c;通过从服务器&#xff0c;虚拟机和网络设备收集的数据提供实时监控&#xff0c;自动发现&#xff0c;映射和可扩展等功能。 Zabbix的企业级监控软件为用户提供内置的Java应用服务器监控&#xff0c;硬件监控&#xff0c…