前天倒腾了一份[SignalR在react/go技术栈的实践], 步骤和思路大部分是外围框架的应用, 今天趁热打铁, 给一个我总结的SignalR避坑指南。

1.SignalR 默认协商

不管是.NET客户端还是JavaScript客户端,构建连接时都存在一个默认配置:SkipNegotiation=fasle,负负得正就等于要求协商,这个默认配置的完整含义是 建立SignalR连接时,客户端要求协商传输方式

对应产生下图:

小技巧:如果你确定你的网络环境能稳定的走websocket传输, 为了快速建立实时通信,可跳过协商请求(设置SkipNegotiation=true), 毕竟每次刷新页面,react组价都会重新加载,重新协商再传输 费时费力。

 const connection = new HubConnectionBuilder()
.withUrl(process.env.REACT_APP_APIBASEURL+"realtime", {
skipNegotiation: true,
transport: HttpTransportType.WebSockets
})
.withAutomaticReconnect()
.withHubProtocol(new JsonHubProtocol())
.configureLogging(LogLevel.Information)
.build();

注意: SkipNegotiation=true,仅限于客户端的传输方式指定为 websocket, 其他方式均会报错。

2.SignalR 传输协商是fetch请求

跟ajax一样,fetch请求也是浏览器脚本的一种,所以很明显也会涉及跨域,标准的CORS方案依然对其有效。

http://localhost:9598/realtime/negotiate?negotiateVersion=1

Post请求

有自定义的请求头 X-Requested-With, X-Signalr-User-Agent

很明显,这又会触发预检Option请求

故你还需要在使用 CORS Middleware时允许这几个自定义请求头。

  // 下面是Go github.com/rs/cors package 支持CORS的代码

	c := cors.New(cors.Options{
// AllowedOrigins: []string{"http://localhost:3000","http://rosenbridge.17usoft.com"},
AllowOriginFunc: func(origin string) bool {
return true
},
AllowedMethods: []string{"POST", "GET", "OPTIONS", "PUT", "DELETE"}, // 下面要加上signalr传输协商要用到的自定义请求头
AllowedHeaders: []string{"Content-Type", "x-requested-with", "x-signalr-user-agent"},
AllowCredentials: true,
Debug: cfg.Log.Debug,
})

3. websocket也有同源限制

ws://localhost:9598/realtime?id=aoSD_WZhqbRfPyXVTYsHig==

WebSocket也有同源限制,但是标准的CORS对其无效,因为CORS解决是HTTP脚本请求的跨域问题,WebSocket说到底不算http协议。

浏览器依旧会为我们携带Origin标头,所以服务端需要验证这些标头,确保只允许来自预期来源的WebSocket。

// 以下是.NET Core 针对websocket同源限制做出的跨域策略

var webSocketOptions = new WebSocketOptions()
{
KeepAliveInterval = TimeSpan.FromSeconds(120),
};
webSocketOptions.AllowedOrigins.Add("https://client.com");
webSocketOptions.AllowedOrigins.Add("https://www.client.com"); app.UseWebSockets(webSocketOptions);

btw, 我使用的GO SignalR库不支持WebSocket跨域, 我提了一个PR, 已经成功合并,兴奋,这是我首次向开源项目提MR且获得通过的项目。

不仅signalr协商请求需要 CORS, 真正传输的websocket协议也有跨域一说,我使用了一个库,没有做到cors,我提了一个mr,成功合并。

4. 部署生产后,需要nginx支持

按照默认配置,一般会先协商,再使用websocket传输。

部署到生产之后,协商后优先使用WebSocket模式, 但是传输失败了, 自动降级为服务器发送事件SSE模式,传输成功。

浏览器开发者工具看不出啥端倪, 使用Fiddler抓包发现 400 状态码

网上搜索了一下,可能是生产的nginx不识别websocket标头。

在nginx配置里面添加如下配置就可以了

location / {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}

关注本公众号的5000+筒靴们应该都知道,本号一直不遗余力的输出原创技术、职场心得,内容说不上什么耳目一新、醍醐灌顶,但号主的技能点一直在进化,本次建立了一个[码甲哥高质量交流群],希望能和童鞋面对面成长(真诚脸图片)。

SingnalR 从开发到生产部署闭坑指南的更多相关文章

  1. RabbitMQ生产部署指南

    像RabbitMQ这样的数据服务通常有许多可调参数.一些配置对开发有很大的意义,但并不适合生产,本指南旨在为此提供帮助 虚拟主机 例如,在单租户环境中,当您的RabbitMQ集群专门为生产中的单个系统 ...

  2. Linux 桌面玩家指南:18. 使用 Docker 隔离自己的开发环境和部署环境

    特别说明:要在我的随笔后写评论的小伙伴们请注意了,我的博客开启了 MathJax 数学公式支持,MathJax 使用$标记数学公式的开始和结束.如果某条评论中出现了两个$,MathJax 会将两个$之 ...

  3. 2016/5/6 thinkphp ①框架 ② 框架项目部署 ③MVC模式 ④控制器访问及路由解析 ⑤开发和生产模式 ⑥控制器和对应方法创建 ⑦视图模板文件创建 ⑧url地址大小写设置 ⑨空操作空控制器 ⑩项目分组

    真实项目开发步骤: 多人同时开发项目,协作开发项目.分工合理.效率有提高(代码风格不一样.分工不好) 测试阶段 上线运行 对项目进行维护.修改.升级(单个人维护项目,十分困难,代码风格不一样) 项目稳 ...

  4. 一个gulp用于开发与生产的示例

    gulp是一款流行的前端构建工具,可以帮我们完成许多工作:监听文件修改.刷新浏览器.编译Less/Scss.压缩代码.添加md5.合并文件等.gulp的配置和使用特别简单,学习gulp过程中顺便写了一 ...

  5. webpack开发与生产环境配置

    前言 作者去年就开始使用webpack, 最早的接触就来自于vue-cli.那个时候工作重点主要也是 vue 的使用,对webpack的配置是知之甚少,期间有问题也是询问大牛 @吕大豹.顺便说一句,对 ...

  6. kettle-数据源配置化-开发、生产采用不同配置

    数据etl常用工具kettle. 1.说明: kettle-数据源配置化:是指kettle的数据源连接信息全部或者部分从配置文件中读取(如果是数据库的资源库,那么资源库也可以配置化). 2.优点: 1 ...

  7. spring boot--日志、开发和生产环境切换、自定义配置(环境变量)

    Spring Boot日志常用配置: # 日志输出的地址:Spring Boot默认并没有进行文件输出,只在控制台中进行了打印 logging.file=/home/zhou # 日志级别 debug ...

  8. 免费开源《OdooERP系统部署架构指南》试读:第一章 Odoo架构概述

    文/开源智造联合创始人老杨 本文来自<OdooERP系统部署架构指南>的试读章节.书籍尚未出版,请勿转载.欢迎您反馈阅读意见. 从web浏览器到PostgreSQL,多层与其他层交互以处理 ...

  9. Laravel本地环境搭建:Homestead开发环境的部署

    Laravel框架在php开发过程是不断进行优化的,当然也包括了本地环境的开发,下面我们就来具体看看laravel框架中的Homestead 开发环境的部署内容. 首先白以下几个概念 VirtualB ...

随机推荐

  1. 超实用的idea技巧,windows技巧,用于节省时间!

    进去https://zhangjzm.gitee.io/self_study 找平常积累,或者其它的

  2. appium+python运行自动化测试提示“find_element() takes from 1 to 3 positional arguments but 14 were given”错误

    1.运行后提示"find_element() takes from 1 to 3 positional arguments but 14 were given",在网上找了很多解决 ...

  3. NOIP模拟14「队长快跑·影魔·抛硬币」

    T1:队长快跑 基本思路:   离散化·DP·数据结构优化DP   这三个我都没想到....气死.   定义状态数组:\(c[i][j]\)表示在i时最小的a值是j时可以摧毁的最多的水晶数.   那么 ...

  4. 页面调用系统window打印

    一. 打印:直接页面调用window.print(),当前页面就会转换成打印页面 当前页面是使用HTML拼接成A4纸表格样式的展示: doPrint:function(type) { // this. ...

  5. eclipes常见操作总结及项目2和3经验总结

    eclipes常见操作总结及项目2经验总结 eclipes提示: 打开eclipes 选择window->perference->java->editor->content a ...

  6. Vue3.x全家桶+vite+TS-构建Vue3基本框架

    目录 一.搭建基础项目 1.vite创建项目 3.运行项目 2.环境变量设置介绍 vite配置多环境打包 二.配置Router 1.安装路由 2.配置路由 3.引入 三.配置Vuex 1.安装vuex ...

  7. FastAPI(7)- get 请求 - 详解 Path

    前言 上一篇讲了可以为查询参数添加额外的校验和元数据,Query 库:https://www.cnblogs.com/poloyy/p/15306809.html 这篇讲可以为路径查询添加额外的校验和 ...

  8. Windows 11抢先体验

    SHA1值: 3B6DA9194BA303AC7DBBF2E521716C809500919C 谷歌云:https://drive.google.com/file/d/1sH0cBI9hwh8EdlV ...

  9. 告别Kafka Stream,让轻量级流处理更加简单

    一说到数据孤岛,所有技术人都不陌生.在 IT 发展过程中,企业不可避免地搭建了各种业务系统,这些系统独立运行且所产生的数据彼此独立封闭,使得企业难以实现数据共享和融合,并形成了"数据孤岛&q ...

  10. 字体小于12px 无法缩小解决方案

    通过缩放进行大小控制. 缩放可能会导致元素也进行缩放.需要注意 transform: scale(0.5);