Django 尝试SSE报错 AssertionError: Hop-by-hop headers not allowed 的分析

情况描述

近期计划测试一下django对日志打印的支持,一般都是用websocket的方式,想测试一下SSE (Server-sent events)的服务端推送,发现过程中存在报错:

Traceback (most recent call last):File "D:\Software\Anaconda3\lib\wsgiref\handlers.py", line 137, in runself.result = application(self.environ, self.start_response)File "D:\IDE Projects\Music\venv\lib\site-packages\django\contrib\staticfiles\handlers.py", line 76, in __call__return self.application(environ, start_response)File "D:\IDE Projects\Music\venv\lib\site-packages\django\core\handlers\wsgi.py", line 142, in __call__start_response(status, response_headers)File "D:\Software\Anaconda3\lib\wsgiref\handlers.py", line 249, in start_responseassert not is_hop_by_hop(name),"Hop-by-hop headers not allowed"
AssertionError: Hop-by-hop headers not allowed

部分代码

    response = HttpResponse(content_type='text/event-stream')response['Cache-Control'] = 'no-cache'# AssertionError: Hop-by-hop headers not allowedresponse['Connection'] = 'keep-alive'response['Transfer-Encoding'] = 'chunked'

初步分析

1)报错大致是说Hop-by-hop headers not allowed ,说是HTTP1.0 不支持这个头部

HTTP 首部字段将定义成缓存代理和非缓存代理的行为,分成 2 种类型。

端到端首部(End-to-end Header)
分在此类别中的首部会转发给请求 / 响应对应的最终接收目标,且必须保存在由缓存生成的响应中,另外规 定它必须被转发。

逐跳首部(Hop-by-hop Header)
分在此类别中的首部只对单次转发有效,会因通过缓存或代理而不再转发。HTTP/1.1 和之后版本中,如果要使用 hop-by-hop 首部,需提供 Connection 首部字段。

2)依据堆栈信息,找到对应的判断函数 is_hop_by_hop(name) ,只要头部存在如下的集合元素,就会被判定为 hop_by_hop

# wsgiref\handlers.pyif __debug__:for name, val in headers:name = self._convert_string_type(name, "Header name")val = self._convert_string_type(val, "Header value")assert not is_hop_by_hop(name),"Hop-by-hop headers not allowed"# handlers\wsgi.py
_hoppish = {'connection':1, 'keep-alive':1, 'proxy-authenticate':1,'proxy-authorization':1, 'te':1, 'trailers':1, 'transfer-encoding':1,'upgrade':1
}.__contains__def is_hop_by_hop(header_name):"""Return true if 'header_name' is an HTTP/1.1 "Hop-by-Hop" header"""return _hoppish(header_name.lower())

3)于是乎,我把Connection 和 Transfer-Encoding 注释掉,就正常了

附带SSE 在django的使用办法

(一)前端 HTML 部分代码

<p id="info">测试</p><script>var need_close = false;var eventSource = new EventSource('/sse');info_elm = document.getElementById("info");// 开启连接的监听// 解决重复请求(默认会无限重连) 也可以由后端内容决定是否关闭eventSource.onopen = function(){if (need_close){eventSource.close();}need_close  = true;};// 收到事件的监听eventSource.onmessage = function(event) {// 处理接收到的事件数据info_elm.innerText = info_elm.innerText + event.data + '\n';};</script>

(二)django

### views.py
from django.http import StreamingHttpResponsedef sse(request):def event_stream():# 测试读取当前文件with open('appname/views.py', encoding='utf-8') as file:for line in file:# time.sleep(1)yield f'data: {line}\n\n'return StreamingHttpResponse(event_stream(), content_type='text/event-stream', headers={'Cache-Control':'no-cache'})def hello(request):return render(request, 'sse.html' )### urls.py
urlpatterns = [path('sse', views.sse),path('hello', views.hello),
]

(三) 结果

http://127.0.0.1:8000/sse

能看到只有一个请求,内容是逐步刷新出来的
在这里插入图片描述

http://127.0.0.1:8000/hello

能看到有三个请求,第二个是SSE请求,结束后,EventSource自动拉起了第三个请求,由于在onopen 配置了变量控制,所以后期不会有新的推送进来导致数据重复载入前端
在这里插入图片描述

(四) 不可行方案
如下方案主要是 response.flush() 并不能把数据刷新到客户端,所以这个与直接返回结果没太大区别,也可能是我目前使用方式不对或理解没到位。

官方文档: response.flush() 这个方法使一个 HttpResponse 实例成为一个类似文件的对象

def sse(request):response = HttpResponse( content_type='text/event-stream')response['Cache-Control'] = 'no-cache'for i in range(5):response.write(f'data:{i} \n\n')response.write('id: {i} ')response.write(f'message: {datetime.datetime.now()}')response.write('event: 发送数据')# 数据发送到客户端response.flush()time.sleep(1)return response

总结

1、发现网上很多给的代码都跑不起来,要么不和预期,终究还是得找官方
2、尝试看看源码,可能能找到问题原因还有一些没接触过的写法
3、可以用while True ,然后将数据读取写入到循环内部,然后通过控制时间间隔来减少推送

参考链接:
HTTP 首部字段详细介绍
Python __debug__内置变量的用法
SSE介绍
W3shcool SSE
关于SSE关闭的问题
EventSource专题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/155195.html

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

相关文章

机器学习-特征选择:如何使用互信息特征选择挑选出最佳特征?

一、引言 特征选择在机器学习中扮演着至关重要的角色&#xff0c;它可以帮助我们从大量的特征中挑选出对目标变量具有最大预测能力的特征。互信息特征选择是一种常用的特征选择方法&#xff0c;它通过计算特征与目标变量之间的互信息来评估特征的重要性。 互信息是信息论中的一…

腾讯待办关停后怎么恢复使用?可自动设置提醒时间的待办工具

你是否曾经有过这样的经历&#xff1a;突然想到一个重要的任务&#xff0c;但却忘记立即记录下来&#xff0c;导致事后无法及时完成&#xff1f;我们的日常生活充满了琐碎的任务&#xff0c;而记录待办事项并设置提醒时间&#xff0c;可以帮助我们更好地组织和管理时间。 记录…

相关性网络图 | 热图中添加显著性

一边学习&#xff0c;一边总结&#xff0c;一边分享&#xff01; 本期教程 写在前面 此图是一位同学看到后&#xff0c;想出的一期教程。 最近&#xff0c;自己的事情比较多&#xff0c;会无暇顾及社群和公众号教程。 1 安装和加载相关的R包 library(ggraph) library(tidy…

标配率破8成,新能源车2025年全面标配!哪些OTA供应商正在领跑

伴随着汽车智能化的加速渗透&#xff0c;软件在线升级&#xff08;OTA&#xff09;也在快速实现从基于软件层的SOTA &#xff0c;到硬件层的FOTA的全面普及。 其中&#xff0c;在行业内&#xff0c;SOTA普遍是指车辆软件应用层的升级&#xff0c;通过网络将文件从云端服务器下…

stream流—关于Collectors.toMap使用详解

目录 使用规则&#xff1a;1.将list转成以id为key的map&#xff0c;value是id对应的某对象2.假如id存在重复值&#xff0c;则会报错Duplicate key xxx3.想获得一个id和name对应的Map<String, String>3.1 name为空时null3.2 id重复时 4.分组 使用groupingby 使用规则&…

Git基础命令实践

文章目录 简介git的安装配置git的安装git的配置 git使用的基本流程创建版本库时光机穿梭版本回退工作区和暂存区管理修改撤销修改删除文件 远程仓库添加远程库从远程库克隆 总结 简介 本文主要记录了我在学习git操作的过程&#xff0c;以及如何使用GitHub。建议先参考廖雪峰的…

AI:45-基于深度学习的声纹识别

🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌本专栏包含以下学习方向: 机器学习、深度学…

Linux--文件操作

1.什么是文件 对于文件来说&#xff0c;文件文件内容文件属性&#xff1b;对于文件来说&#xff0c;只有两种操作&#xff0c;对内容的修改和对文件属性的修改&#xff0c;这就是文件的范畴。 对于存放在磁盘上的文件&#xff0c;我们需要通过进程来进行访问&#xff0c;访问文…

【JQuery-XSS漏洞(CVE-2020-11022/CVE-2020-11023)漏洞复现】

文章目录 一、漏洞描述二、受影响版本三、漏洞复现四、漏洞危害五、修复建议 一、漏洞描述 进行在公司内部用nessus做漏洞扫描时&#xff0c;发现某台服务器报出这个中危漏洞&#xff0c;后面查资料复现。 根据脚本中的自我报告版本&#xff0c;远程web服务器上托管的JQuery版…

2024年湖北武汉建筑企业三类人员安全员ABC怎么报考

2024年湖北武汉建筑企业三类人员安全员ABC怎么报考 武汉建筑企业报考三类人员&#xff0c;建筑单位归属地在武汉&#xff0c;且有建筑相关的一些资Z&#xff0c;才可以申报一定数量的三类人员、安全员ABC、建筑安全员ABC、专职安全员C证、建设厅安全员ABC证。 建筑企业-报考建…

IDEA 使用技巧

文章目录 语言支持简化编写 有问题&#xff0c;可暂时跳过 个人常用快捷键插件主题插件功能插件 碰到过的问题 除了一些在Linux上用vim开发的大佬&#xff0c;idea算是很友好的集成开发工具了&#xff0c;功能全面&#xff0c;使用也很广泛。 记录一下我的 IDEA 使用技巧&#…

TestCenter测试管理工具

estCenter&#xff08;简称TC&#xff09;一款广受好评的测试管理工具&#xff0c;让测试工作更规范、更有效率&#xff0c;实现测试流程无纸化&#xff0c;测试数据资产化。 产品概述 TC流程图 产品功能 一、案例库 案例库集中化管理&#xff0c;支持对测试用例集中管理&…