前天倒腾了一份[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 ...

  10. AppBoxFuture实战: 如何同步开发与生产环境的模型

      框架是用抽象模型驱动的方式来生成应用系统的,这样可以将这些模型序列化为相应的模型包文件,通过反序列化导入至其他部署环境内,从而实现开发环境与生产环境的同步,包括对应的数据库结构的同步.下面通过示例 ...

随机推荐

  1. iOS. PercentEscape是错用的URLEncode,看看AFN和Facebook吧

    别再使用stringByAddingPercentEscapesUsingEncoding 当遇到发送网络请求的参数中有汉字的情况,很多人一股脑地使用stringByAddingPercentEsca ...

  2. 如何在linux下录制terminal操作?

    相关包: ttyrec: ttyrec is a tty recorder. Recorded data can be played back with the included ttyplay co ...

  3. 【ODI】| 数据ETL:从零开始使用Oracle ODI完成数据集成(三)

    资料库的创建.体系结构的创建.模型反向工程都已经完成了,下面就是创建以及执行接口来完成工作了. 浏览前两节请点击: [ODI]| 数据ETL:从零开始使用Oracle ODI完成数据集成(一) [OD ...

  4. [转]OpenShift 集群搭建指南

    转自:http://www.cnblogs.com/zhangning/p/7251810.html OpenShift 集群搭建指南 v1.0 搭建Hyper-v虚拟机或物理机 配置物理机静态IP, ...

  5. Linux-学习patch命令打补丁,diff命令制作补丁(3)

    patch:通过补丁文件,来对原文件打补丁 diff:      比较两个文件,然后生成一个补丁文件 1.patch用法    patch -p[剥离层级]  <[补丁文件] 2.patch命令 ...

  6. Python之面向对象编程学习

    不知不觉,学到了python的面向对象编程思想.今天我们来讨论下面向对象编程的思想. 顾名思义,面向对象,就是面向于对象,这里所说的对象不是你现实生活中你的女朋友,你的老婆,你的爱人,在编程的世界里面 ...

  7. 1.3.8、CDH 搭建Hadoop在安装之前(端口---Apache Flume和Apache Solr使用的端口)

    Apache Flume和Apache Solr使用的端口 Apache Flume用于与Apache Solr通信的端口可能会有所不同,具体取决于您的配置以及是否使用安全性(例如,SSL).使用Fl ...

  8. random库的常见用法

    import random print( random.randint(1,10) ) # 产生 1 到 10 的一个整数型随机数 print( random.random() ) # 产生 0 到 ...

  9. InnoDB的锁机制浅析(All in One)

    目录 InnoDB的锁机制浅析 1. 前言 2. 锁基本概念 2.1 共享锁和排它锁 2.2 意向锁-Intention Locks 2.3 锁的兼容性 3. InnoDB中的锁 3.1 准备工作 3 ...

  10. 五、搭建kube-dns

    1. 简介   kube-dns用来为kubernetes service分配子域名,在集群中可以通过名称访问service.通常kube-dns会为service赋予一个名为"servic ...