requests.exceptions.ChunkedEncodingError: ('Connection broken: IncompleteRead(0 bytes read)', Incomp

部署运行你感兴趣的模型镜像

解决了之前的报错:
我的环境:
linux_centos python2.7

报错情况:

Traceback (most recent call last):
File "total_flow_count.py", line 89, in  <module>
query_total_flow()
File "total_flow_count.py", line 59, in query_total_flow
response = requests.post(url, json=data, timeout=60, headers=request_header)
File "/usr/lib/python2.7/site-packages/requests/api.py", line 112, in post
return request('post', url, data=data, json=json, **kwargs)
File "/usr/lib/python2.7/site-packages/requests/api.py", line 58, in request
return session.request(method=method, url=url, **kwargs)
File "/usr/lib/python2.7/site-packages/requests/sessions.py", line 508, in request
resp = self.send(prep, **send_kwargs)
File "/usr/lib/python2.7/site-packages/requests/sessions.py", line 658, in send
r.content
File "/usr/lib/python2.7/site-packages/requests/models.py", line 823, in content
self._content = bytes().join(self.iter_content(CONTENT_CHUNK_SIZE)) or bytes()
File "/usr/lib/python2.7/site-packages/requests/models.py", line 748, in generate
raise ChunkedEncodingError(e)
requests.exceptions.ChunkedEncodingError: ('Connection broken: IncompleteRead(0 bytes read)', IncompleteRead(0 bytes read))

[root@TENCENT64 /data/test]#

2019-7-31日更新:

经过了一段时间的学习,我对这个问题有了更深的理解,也有了更好的解决方案,
和大家分享一下,哈哈~~

chunkedEncodingError ,有时候在调用公司接口的时候,会出现很多问题,
我看了下文档日期,基本都在2013-2014年,
所以我想,会不会是因为协议不统一导致的呢???
也就是,我们的请求requests默认了是http1.1,但是对方服务器接口发送的却是http1.0的格式,
于是上网搜索,啥也没有搜索到,我决定自己动手,丰衣足食:
先查看错误位置:
在这里插入图片描述
于是打开那个文件:

vim /usr/lib/python2.7/site-packages/requests/models.py

跑到第753行去看:
发现捕获了一个协议错误,然后抛出了chunkedEncoding异常,
很明显了。就是这个服务器支持http1.0,我们跑去拿http1.1访问,出了一些兼容性上的问题。
在这里插入图片描述
之前我的想法就是,一言不合改源码,但是换了一台机器去部署,你也让别人改源码吗?(手动滑稽)
改完代码的返回的请求头:http1.1传输,强行chunked
在这里插入图片描述
没改之前的返回的请求头:http1.0传输,
在这里插入图片描述
HTTP1.1支持chunked transfer,所以可以有Transfer-Encoding头部域:Transfer-Encoding: chunked,简单说就是返回内容的时候,分段返回的。chunked的编码是吧整个压缩包分段传输,其实有点像我们把压缩包压缩时分成若干个压缩文件一样,解压的时候,必须把全部文件放到一个目录下解压缩。这个编码也是如此,传过来的是一个一个块,最后需要把这些块都拼接起来才是完整的数据,所以,只要一次把这些块取出来拼到一块就可以了。不设置长度。
chunked编码在压缩块前面都会有一个标识压缩块大小的16进制字符串,我们每次读取压缩块之前,需要先获得这个大小,以便告诉程序接下来该读取多少数据,最后用一个零长度的块作为消息结束的标志。这种方法允许发送方只缓冲消息的一个片段,避免缓冲整个消息带来的过载。
因为上面的服务器不支持chunked传输,从而一开始还没传数据,就报错了。

参考网站:https://blog.youkuaiyun.com/lhj_5460/article/details/48156461

HTTP1.0则没有。 HTTP通信时,会使用Content-Length头信息性来通知用户代理(通常意义上是浏览器)服务器发送的文档内容长度,该头信息定义于HTTP1.0协议RFC 1945 10.4章节中。浏览器接收到此头信息后,接受完Content-Length中定义的长度字节后开始解析页面,但如果服务端有部分数据延迟发送吗,则会出现浏览器白屏,造成比较糟糕的用户体验。

如果是chunked传输,那么Content-Length就会自动被失效

所以这里服务器端是http1.0。改包源代码,用chunked传输,自然就会导致Content-Length失效,如果文本接收太长,他也不知道文本没有收完,变成了一个小傻子。
而所谓的chunked编码,因为有版本ProtocolError异常被捕获了,从而其实根本没有用到chunked编码!!!
这报了异常,代码的确是不安全的,所以我们应该考虑的是降低发送请求的版本。
其他的都别动了,就加上三句话就ok:

import httplib 
httplib.HTTPConnection._http_vsn = 10 
httplib.HTTPConnection._http_vsn_str = 'HTTP/1.0'

之前看网上有人用curl,然后设置http协议为1.0什么的,这个也是一样的思路。
然后就可以正常跑起来拉!

遇到了chunk编码的其他问题?

别怕,按照上面的思路去解决就好,
1.报了什么错误,按照路径打开源文件去检查报错和捕获异常情况,requests包写的很优雅,别怕,注释也写了很多滴!
2.如果是DecodeError错误:

  1. 是不是对方发的报文格式或者协议版本和你的接收格式不同?只能你适应他的话,你就得做相应修改,
  2. 是不是编解码方式错误?

原文:

解决方法如下:

在这里插入图片描述

可以看到,划红线的地方报错了,具体位置在:

File "/usr/lib/python2.7/site-packages/requests/models.py", line 748, in generate

让我觉得很奇葩的是,这个报错居然是可以去掉的。于是我跑到这个models.py里面,把raise给去掉了,然后就成功运行了。

bug原因

这是为什么呢?
网上有些人的情况是:
在这里插入图片描述
画了红色圈圈的地方是并不是0的,他们能获得一些数据,偶尔能够连上。
这个应该看下面的网址:https://blog.youkuaiyun.com/wangzuxi/article/details/40377467
而我呢?非常凄惨,连都连不上。
于是:
问题一:真的能跑通吗?
在办公网络上的浏览器测试网址:

http://xxx.xxx.xxx.xxx:80/xxxxx/xxxxx/xxxxx.cgi/json?data={"operator":"xxxxx","feature_type":["出包量"],"date":"2019-06-15","begintime":"23:55","endtime":"23:59","type":"set","set_id":[1],"set_name":[]}

在idc(内网机器)的测试机器上:

curl -1d 'data={"operator":"xxxxx","feature_type":["出包量"],"date":"2019-06-15","begintime":"23:55","endtime":"23:59","type":"set","set_id":[1],"set_name":[]}' "http://xxx.xxx.xxx.xxx:80/xxxxx/xxxxx/xxxxx.cgi"

都可以运行,没毛病。。。说明是requests这个过程出了问题。
于是我继续努力的写着,参考下面的网址:
http://blog.sina.com.cn/s/blog_a1e9c7910102x4ux.html
是我同事写的他遇到的情况。
然而并没有用。

当我去掉一切json的参数,直接用py脚本访问那个接口(ip+定位符)时,又是可以访问的。
我知道了,问题出在参数上,
可能是传参出了问题,post阶段出错。
但是你仔细想一下,它什么都没有接收到,应当是连接过程出了问题。
很有可能是返回的值编码有问题。
所以根据我的猜想,看了下chunk编码的知识:
https://blog.youkuaiyun.com/zhangboyj/article/details/6236780

一般HTTP通信时,会使用Content-Length头信息性来通知用户代理(通常意义上是浏览器)服务器发送的文档内容长度,该头信息定义于HTTP1.0协议RFC 1945 10.4章节中。浏览器接收到此头信息后,接受完Content-Length中定义的长度字节后开始解析页面,但如果服务端有部分数据延迟发送吗,则会出现浏览器白屏,造成比较糟糕的用户体验。
解决方案是在HTTP1.1协议中,RFC 2616中14.41章节中定义的Transfer-Encoding: chunked的头信息,chunked编码定义在3.6.1中,所有HTTP1.1 应用都支持此使用trunked编码动态的提供body内容的长度的方式。进行Chunked编码传输的HTTP数据要在消息头部设置:Transfer-Encoding: chunked表示Content Body将用chunked编码传输内容。根据定义,浏览器不需要等到内容字节全部下载完成,只要接收到一个chunked块就可解析页面.并且可以下载html中定义的页面内容,包括js,css,image等。
采用chunked编码有两种选择,一种是设定Server的IO buffer长度让Server自动flush buffer中的内容,另一种是手动调用IO中的flush函数。不同的语言IO中都有flush功能……

简而言之,chunked编码的基本方法是将大块数据分解成多块小数据,每块都可以自指定长度,
这里会出错,也许是因为对方使用了http1.0或者是两者不匹配,等等。

这个问题对于数据传输来说,
http1.1是致命的,http1.0根本不会看chunked编码长度,

所以解决方案可以有很多:

1.修改python源码,把报错去掉(去掉后如果你的代码没有问题,就可以传输了)
2.使用http1.0来进行request
3.不用requests,用python curl等等。
4.也许更新python的requests库会有用。
5.加版本声明:

import httplib
httplib.HTTPConnection._http_vsn = 10
httplib.HTTPConnection._http_vsn_str = 'HTTP/1.0'

我的请求代码格式:

#-*- coding:utf-8 -*-
import time
import hmac
import hashlib
import requests
import json
import mysql.connector
import requests
import httplib
import urllib
from urllib import unquote
httplib.HTTPConnection._http_vsn = 10
httplib.HTTPConnection._http_vsn_str = 'HTTP/1.0'

import json

def query_total_flow():
    header = {"Content-Type": "application",  'Connection': 'close', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}

    post_data = {
        "operator": "xxxxxx",  # 调用系统的名字
        "type": "set",  
        "set_id": [1],  
        "set_name": [],
        "feature_type": ["入流量"],
        "date": "2019-06-15",
        "begintime": "23:55",
        "endtime": "23:59",
    }
    url = "http://xxx.xxx.xxx.xxx:80/xxxxx/xxxxx/xxxxx.cgi/json?"  
    post_data = json.dumps(post_data, ensure_ascii=False, separators=(',',':'))  
    print post_data
   # url = url + post_data
    url = url + urllib.urlencode({'data': post_data})
    
   # data = urllib.urlencode({'data': post_data})
   # print post_data
   # print data
   # data = unquote(data)
    try:
   #    print data
        print url
        response = requests.get(url, timeout=60, headers=header)
        
        print response.headers
        print response.url
        print response.text.encode('utf-8')
        

        response = urllib.unquote(response)
        print response
 
      

if __name__ == "__main__":
	query_total_flow()



或者用post也可以,上面的代码里url要注意加json?
整体代码如下:

#-*- coding:utf-8 -*-
import time
import hmac
import hashlib
import requests
import json
import mysql.connector
import requests
import httplib
import urllib
from urllib import unquote

import json

def query_total_flow():
    header = {"Content-Type": "application/json",  'Connection': 'close', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}

    post_data = {
        "operator": "xxxxxx",  # 调用系统的名字
        "type": "set",  
        "set_id": [1],  
        "set_name": [],
        "feature_type": ["入流量"],
        "date": "2019-06-15",
        "begintime": "23:55",
        "endtime": "23:59",
    }
    url = "http://xxx.xxx.xxx.xxx:80/xxxxx/xxxxx/xxxxx.cgi/json?"  
    post_data = json.dumps(post_data, ensure_ascii=False, separators=(',',':'))  
    print post_data
   # url = url + post_data
    url = url + urllib.urlencode({'data': post_data})
    
   # data = urllib.urlencode({'data': post_data})
   # print post_data
   # print data
    data = unquote(url)
    try:
   #    print data
        print data
        response = requests.get(url, json=data, timeout=60, headers=header)
        
        print response.headers
        print response.url
        print response.text.encode('utf-8')

 
        if response['code'] != 0:
            result_dict = json.loads(response.text)
            data = result_dict["data"]
            print(data)
            print(data)
            set_info = []  
            return response
            raise exp_with_err_instance(err.RESULT_ERROR, 'can not find inst info')
            print ("none!")
            return []
    except Exception as e:
        print ("Exception")
        raise

if __name__ == "__main__":
	query_total_flow()

您可能感兴趣的与本文相关的镜像

Python3.10

Python3.10

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

<think>首先,用户的问题是关于处理 Pythonrequests 库中的 `requests.exceptions.ChunkedEncodingError` 异常,具体是 "Connection broken: IncompleteRead" 错误。我需要基于提供的引用信息来构建一个解决方案。 从引用中提取关键点: - [^1]: 提到一个 Stack Overflow 链接,但具体内容未提供。 - [^2]: 用户尝试了多种方法,包括使用 HTTP/1.0、更新库、修改源码,但未解决。建议使用循环重试机制。 - [^3]: 类似问题,建议在请求中添加 `stream=True` 参数。 - [^4]: 问题可能由于服务器缺少 'x-content-type-options' 头部,建议手动设置该头部。 - [^5]: 提供了代码示例:检查并设置 'x-content-type-options' 为 'nosniff'。 用户的需求是解决这个异常,所以我需要提供一个清晰的、逐步的解决方案。 结构化我的回答: 1. **理解问题**:解释 `ChunkedEncodingError` 是什么,为什么发生(连接中断导致数据读取不完整)。 2. **解决方案**: - 推荐方法:使用 `stream=True` 参数(从引用[^3])。 - 重试机制:使用循环重试(从引用[^2])。 - 设置头部:手动添加 'x-content-type-options' 头部(从引用[^5])。 - 其他建议:确保 requests 库更新,使用 HTTP/1.0 等。 3. **代码示例**:提供 Python 代码来演示如何实现这些解决方案。 4. **生成相关问题**:在末尾添加相关问题,以鼓励进一步学习。 确保回答符合系统级指令: - 行内数学表达式用 `$...$`,但这里可能不需要,因为主题是编程。 - 独立公式用 `$$...$$`,但可能不适用。 - LaTeX 语法正确:在代码块中不需要 LaTeX。 - 使用中文回答。 - 生成相关问题。 - 在引用的段落末尾添加引用标识,例如 [^1]。 在回答中,自然地引用提供的引用源: - 当提到某个方法时,加上引用标识,如 [^2] 或 [^3]。 最终回答结构: - 开头:介绍问题和原因。 - 主体:逐步解决方案,每个方法详细说明。 - 代码示例:展示关键方法。 - 结尾:总结和建议。 - 相关问题:生成几个相关问题。 相关问题想法: 1. 如何防止 requests 库中的连接中断错误? 2. 除了重试机制,还有哪些处理网络异常的策略? 3.Python 中,如何优化 requests 库的性能以避免此类错误? 4. 服务器端如何配置以避免 'IncompleteRead' 错误? 5. 比较不同 HTTP 版本对请求稳定性的影响。 现在,构建回答。</think>### 解决 requests.exceptions.ChunkedEncodingError: IncompleteRead 连接中断问题 在 Pythonrequests 库中,`requests.exceptions.ChunkedEncodingError: ('Connection broken: IncompleteRead(...)')` 错误通常发生在网络连接不稳定或服务器响应异常时,导致数据块传输中断,无法完整读取响应内容。这常见于处理大文件下载、流式传输或特定服务器配置场景。以下我将逐步解释原因并提供已验证的解决方案,所有方法均基于实际案例和引用资料[^2][^3][^4][^5]。 #### 问题原因分析 - **核心问题**:网络连接意外中断(如超时、服务器断开或代理问题),导致响应数据读取不完整。 - **触发场景**: - 服务器使用分块传输编码(Chunked Transfer Encoding),但传输中途失败。 - 服务器响应头缺失安全字段(如 `x-content-type-options`),引发客户端解析错误[^5]。 - 网络延迟高或请求超时设置不合理。 - **常见表现**:下载文件、API 请求或爬虫任务时随机出现异常。 #### 逐步解决方案 以下是多种有效方法,按推荐优先级排序。建议从方法1开始尝试,逐步测试。 1. **使用 `stream=True` 参数并分块读取数据** 这是最推荐的方案,能显式控制数据流传输,避免一次性加载大响应导致的错误[^3][^4]。 - **原理**:`stream=True` 启用流式传输,将响应拆分为小数据块,减少单次读取压力。 - **步骤**: - 在请求中添加 `stream=True`。 - 使用迭代器逐块读取内容。 - **代码示例**: ```python import requests url = "https://example.com/large-file" try: response = requests.get(url, stream=True, timeout=30) # 设置超时时间 response.raise_for_status() # 检查HTTP状态码 # 分块读取响应内容 with open('output.file', 'wb') as f: for chunk in response.iter_content(chunk_size=8192): # 推荐块大小 8KB if chunk: # 过滤空块 f.write(chunk) except requests.exceptions.ChunkedEncodingError as e: print(f"连接中断错误: {e}") # 添加重试逻辑(见方法2) except requests.exceptions.RequestException as e: print(f"请求异常: {e}") ``` 2. **添加重试机制处理临时中断** 如果方法1无效,可能是间歇性网络问题,需实现自动重试[^2][^3]。 - **原理**:通过循环捕获异常并重试请求,补偿不稳定连接。 - **步骤**: - 使用 `while` 循环或第三方库(如 `tenacity`)。 - 设置最大重试次数和延迟,避免无限循环。 - **代码示例**: ```python import requests import time def safe_request(url, max_retries=3, delay=2): retries = 0 while retries < max_retries: try: response = requests.get(url, stream=True, timeout=30) response.raise_for_status() return response # 成功时返回响应 except requests.exceptions.ChunkedEncodingError: retries += 1 print(f"重试中 ({retries}/{max_retries})...") time.sleep(delay) # 延迟后重试 raise Exception("重试多次后失败") # 使用示例 try: response = safe_request("https://example.com") # 处理响应内容... except Exception as e: print(e) ``` 3. **手动设置响应头 `x-content-type-options`** 某些服务器配置问题可通过强制添加安全头部解决[^5]。 - **原理**:缺失 `x-content-type-options` 头部可能导致浏览器或客户端解析混乱,手动设置可规避错误。 - **步骤**: - 检查响应头是否包含该字段。 - 如果缺失,则手动添加并设置为 `nosniff`。 - **代码示例**: ```python import requests url = "https://example.com" response = requests.get(url) # 检查并设置头部 if 'x-content-type-options' not in response.headers: response.headers['x-content-type-options'] = 'nosniff' # 验证设置 assert response.headers.get('x-content-type-options') == 'nosniff', "头部设置失败" # 继续处理响应... ``` 4. **其他辅助优化方法** - **更新 requests 库**:确保使用最新版本(如 `pip install --upgrade requests`),修复已知 bug[^2][^3]。 - **切换 HTTP 协议版本**:尝试强制使用 HTTP/1.0(添加 `headers={'Connection': 'close'}`),避免分块传输问题[^4]。 - **调整超时设置**:增加 `timeout` 值(如 `timeout=60`),给网络更多缓冲时间。 - **检查网络环境**:使用稳定网络,或添加代理设置(如 `proxies={'http': 'http://user:pass@proxy:port'}`)。 #### 总结建议 - **首选方案**:结合方法1(`stream=True`)和方法2(重试机制)在大多数情况下有效[^3][^4]。 - **测试顺序**:先尝试简单修复(如更新库或设置头部),再实施重试逻辑。 - **预防措施**:监控服务器响应头,确保包含 `x-content-type-options: nosniff`[^5],并在客户端代码中添加错误日志。 - **性能影响**:`stream=True` 可能轻微增加内存开销,但显著提升大文件处理的稳定性。 如果问题持续,请提供更多上下文(如完整错误日志或请求 URL),以便进一步诊断。
评论 9
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值