前端点一个按钮, 发送一个 ajax, 后端开始做动作,同时不停的将处理进度实时推送给前端.
现在的思路是, 前端和后端 ajax 同时绑定同一个 group. 后端给 group 发消息, websocket 接什么消息发什么消息,向同一个 group. 这样前端就收到消息了.
def view(request):
    ws = websocket(***)
    # do something business logic
    ws.send()
    return 666
伪代码大概是这样的,但是 websocket server 端的心跳机制会导致和 view 里面创建的 ws 客户端失去连接.
现在的解决方案是, 在 view 里面创建一个线程, 在新起的线程里面 不停的发消息给 websocket server.
拍脑袋感觉,应该在 view 里面做一个非阻塞带回调的 websocket 客户端,但是...如何实现呢...
实际效果
 逻辑框图
逻辑框图

|  |      1halk      2019-09-26 19:05:29 +08:00 1. websocket server 端的心跳机制会导致和 view 里面创建的 ws 客户端失去连接. --这句话怎么理解? 2. 试试 SSE,能满足你的需求吗 | 
|  |      2wolfie      2019-09-26 19:17:59 +08:00 ws 不是长连接吗,为什么会断开。 客户端定时检查连接是否可用,断了就重连。 | 
|      3Carseason      2019-09-26 19:25:53 +08:00 websocket 是长连接,你心跳也不需要把当前的断开重连吧? 服务端应该把客户端存到一个队列里面,然后当服务端接收到新消息后对该队列推送消息来实现广播 | 
|      4hantsy      2019-09-26 20:39:54 +08:00 SSE 比较适合 | 
|      5kxiaong      2019-09-26 20:57:06 +08:00 拍脑袋想, 你这样子连 websocket 链接也创建不起来吧? 并不是你在 server 端起一个 websocket server,然后不停的 send,客户端就会接收数据。 在 websocket 链接创建之前还有 http 报文做协商认证和链接过程。 websocket 的第一个报文是这样的 (ietf rfc 7977): ``` GET / HTTP/1.1 Host: a.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Origin: http://www.example.com Sec-WebSocket-Protocol: msrp Sec-WebSocket-Version: 13 ``` 一个可能的办法是: 页面先跟 server 创建一个 websocket 链接,使用 groupId 标识这个链接。 页面点击动作的 ajax 将自己的 groupId 作为参数传入 view。view 触发业务逻辑以后就返回 ok, 不需要阻塞等待。 业务逻辑处理过程中的进度信息,通过 websocket 推送到 client | 
|      6neoblackcap      2019-09-26 21:01:42 +08:00 via iPhone websocket 之类的长连接就该用 Tornado 之类的框架,一般基于 request-response 的框架当然会断 | 
|  |      7KuroNekoFan      2019-09-26 21:03:53 +08:00 via iPhone 你这提问看得我一头雾水 | 
|  |      821paradox      2019-09-26 21:17:37 +08:00 用 server send events 吧,sse 或者前端轮询 | 
|  |      9mengqi      2019-09-26 21:31:58 +08:00 看了几遍题主的说明,最后终于确认:没看懂… 1. 为什么前后端不能直接建立 websocket 长连接,而需要一个 group ? 2. “server 端的心跳机制”是指服务器向客户端发送心跳还是客户端向服务端发送心跳?又为什么会导致客户端断开连接? 3. 你贴的伪代码是服务端的代码吗?为什么后面的解决方案又说“在 view 里面创建一个线程, ……不停的发消息给 websocket server”? | 
|  |      10zhuzhibin      2019-09-26 22:12:30 +08:00 via iPhone 连接成功做你需要做的事 如果断了自己做一次重连 | 
|  |      11izoabr      2019-09-26 23:15:19 +08:00 我是直接用 rabbitmq 的 websocket,然后后台和前台都连一下,前台监控队列做回调显示进度就好了。 | 
|  |      12chaleaochexist OP @mengqi 我当时问这个问题的时候就想到了可能看不懂... 一会儿主贴补一个框图...供您参考. 1. 为什么前后端不能直接建立 websocket 长连接,而需要一个 group ? 前端 后端 wsserver 我们现在有这三个实例, 后端需要将消息发送给前端 通过 ws. name 后端和 ws 之间需要通信,我们通过 ws. 否则 ws 后端接到的消息如何推送给前端? 2. “server 端的心跳机制”是指服务器向客户端发送心跳还是客户端向服务端发送心跳?又为什么会导致客户端断开连接? 这个是 server 向 client 发送心跳, 断开连接是服务端(daphne)的配置,心跳间隔 20s.超过 20s 就主动断开连接. 修改心跳间隔是解决思路之一,但是目前我们并不想采用. 3. 你贴的伪代码是服务端的代码吗?为什么后面的解决方案又说“在 view 里面创建一个线程, ……不停的发消息给 websocket server”? 是后端的代码,后端属于 ws 客户端. 前端也是 ws 客户端. 因为,如果客户端不停的给 ws 服务端,那么服务端就不会,也不需要发送心跳了. | 
|  |      13chaleaochexist OP @neoblackcap 可不可以把一个 ws client 做成 异步形式? 现在的项目就是用 django 做的,不可能为了一个 api 换框架啊.代价大了点. | 
|  |      14chaleaochexist OP | 
|      15neoblackcap      2019-09-27 07:33:54 +08:00 via iPhone @chaleaochexist 那你去用 Django 官方出的 channel 啊 | 
|  |      16Nasei      2019-09-27 08:12:39 +08:00 via Android 这么麻烦的吗…进度更新只用过 netcore 的 signalR,基本傻瓜式操作 | 
|  |      17zazalu      2019-09-27 08:39:40 +08:00 没看懂+1 不过我是因为菜没看懂 mark 下 | 
|  |      19b821025551b      2019-09-27 08:59:10 +08:00  1 这个是 server 向 client 发送心跳, 断开连接是服务端(daphne)的配置,心跳间隔 20s.超过 20s 就主动断开连接. 修改心跳间隔是解决思路之一,但是目前我们并不想采用. ----------------------------------------------- 怎么总觉得怪怪的?正常心跳 1s 一个,20s 是没收到心跳就断了;你这是设置了 40s 一个心跳然后 20s 没心跳就断了? 不想修改心跳是什么鬼? 还有,即使是断了,再请求一个重连不就行了?想那么麻烦干吗? | 
|  |      20chaleaochexist OP @b821025551b 谢谢,最后一句话有用.我没想到. 心跳就是 20s 间隔.我看代码默认是这个配置.超过 20S(这个是心跳间隔)+30S(这个是 timeout) 就会主动断开连接. 忘记是 channel 还是 daphne 的代码了.\ ``` class Server(): def __init__(): pass # 就在这里 ``` @neoblackcap 谢谢我用的就是 channel,另外本问题和 ws server 端没有太大关系,我的问题是如何做一个异步非阻塞的 ws 客户端.channel 还支持客户端吗?像 aiohttp 那样? | 
|  |      21tanszhe      2019-09-27 09:16:10 +08:00 这么简单的问题 ,搞不清楚 …… | 
|      22MonoLogueChi      2019-09-27 09:31:29 +08:00 via Android @Nasei signalR 吹?我也喜欢用 | 
|  |      23LeeSeoung      2019-09-27 09:36:33 +08:00 ws 不是双向的么。。没搞明白你想做啥。。为啥 ws 会自己断。。 | 
|  |      24chaleaochexist OP @LeeSeoung 和本题无关的一种可能, timeout 不就断了吗?很好理解. | 
|  |      25shuizhengqi      2019-09-27 10:38:58 +08:00 直接 setInterval 不好使么? | 
|  |      26shuizhengqi      2019-09-27 10:39:39 +08:00 1s 一次,就能做到跟实时差不多的效果 | 
|      27zpf      2019-09-27 11:34:47 +08:00 前端不应该直接请求 websocket 服务器,为什么还要先请求 view 层,view 层在做请求转发? | 
|  |      28chaleaochexist OP @shuizhengqi 当然可以 setInterval 直接发 ajax 就可以了,和 websocket 有啥关系? @zpf 实时推送后台的处理进度. view 在做一个业务逻辑,并将业务逻辑的进度发送给前端. 你的意思是说,这个业务逻辑不用 ajax 而是用 websocket 来实现是吗? | 
|  |      29hsfzxjy      2019-09-27 12:25:18 +08:00 via Android django channels,了解一下 | 
|  |      30chaleaochexist OP @hsfzxjy 谢谢我用的就是 channel,另外本问题和 ws server 端没有太大关系,我的问题是如何做一个异步非阻塞的 ws 客户端.channel 还支持客户端吗?像 aiohttp 那样? |