如何解决Python - 如果服务器在 PUT 完成之前回答,则 HTTP 模块无法解析响应
我正在使用 requests
(它使用 urllib3
和底层的 Python http 模块)库从 Python 脚本上传文件。
我的后端首先检查请求的标头,如果它不符合所需的先决条件,它会立即停止请求并以有效的 400 响应进行响应。
此行为在 Postman 或 Curl 中运行良好;即客户端能够解析 400 响应,即使它没有完成上传并且服务器过早地响应。
但是,在 Python 中使用 requests
/urllib3
执行此操作时,库无法处理后端响应:
Traceback (most recent call last):
File "C:\Users\Neumann\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\urllib3\connectionpool.py",line 670,in urlopen
httplib_response = self._make_request(
File "C:\Users\Neumann\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\urllib3\connectionpool.py",line 392,in _make_request
conn.request(method,url,**httplib_request_kw)
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.8_3.8.1776.0_x64__qbz5n2kfra8p0\lib\http\client.py",line 1255,in request
self._send_request(method,body,headers,encode_chunked)
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.8_3.8.1776.0_x64__qbz5n2kfra8p0\lib\http\client.py",line 1301,in _send_request
self.endheaders(body,encode_chunked=encode_chunked)
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.8_3.8.1776.0_x64__qbz5n2kfra8p0\lib\http\client.py",line 1250,in endheaders
self._send_output(message_body,line 1049,in _send_output
self.send(chunk)
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.8_3.8.1776.0_x64__qbz5n2kfra8p0\lib\http\client.py",line 971,in send
self.sock.sendall(data)
ConnectionResetError: [WinError 10054] Une connexion existante a dû être fermée par l’hôte distant
因为服务器在传输完成前应答,它错误地认为连接已中止,即使服务器确实返回了有效响应。
有没有办法避免这种情况并解析响应?
重现问题的步骤:
- 下载 minIO:https://min.io/download#/
- 运行 minIO :
export MINIO_ACCESS_KEY=<access_key>
export MINIO_SECRET_KEY=<secret_key>
.\minio.exe server <data folder>
- 运行以下脚本:
import os
import sys
import requests
from requests_toolbelt.multipart.encoder import MultipartEncoder
def fatal(msg):
print(msg)
sys.exit(1)
def upload_file():
mp_encoder = MultipartEncoder(fields={'file': (open('E:/Downloads/kek.mp3','rb'))})
headers = { "Authorization": "invalid" }
print('Uploading file with headers : ' + str(headers))
upload_endpoint = 'http://localhost:9000/mybucket/myobject'
try:
r = requests.put(upload_endpoint,headers=headers,data=mp_encoder,verify=False)
except requests.exceptions.ConnectionError as e:
print(e.status)
for property,value in vars(e).items():
print(property,":",value)
fatal(str(e))
if r.status_code != 201:
for property,value in vars(r).items():
print(property,value)
fatal('Error while uploading file. Status ' + str(r.status_code))
print('Upload successfully completed')
if __name__ == "__main__":
upload_file()
如果你用这个更改请求行,它将起作用(即服务器返回 400 并且客户端能够解析它):
r = requests.put(upload_endpoint,data='a string',verify=False)
EDIT :我更新了回溯并更改了问题标题以反映它既不是 requests
也不是 urllib3
错误的事实,而是两者都使用的 Python http 模块。
解决方法
这个问题应该在 urllib3 v1.26.0 中修复。您运行的是哪个版本?
问题是服务器在响应400后关闭连接,所以当urllib3试图继续向它发送数据时,socket就关闭了。所以它并不是真的错误地认为连接已关闭,它只是对这种情况处理不当。
您的示例代码在我的机器上运行良好,使用 urllib3==1.26.0 。但是我注意到您在 Windows 计算机上遇到了不同的异常,因此修复程序可能不起作用。在这种情况下,我只会捕获异常并向 urllib3 的维护者提交错误报告。
,您应该尝试 requests.get 而不是 put 并检查它是否有效。请在下面找到我的示例代码。
try:
output = requests.get('http://' + <ipaddress>)
status = output.status_code
print(status)
if status == 200:
print("PASS: HTTP is successful")
else:
raise RuntimeError("FAIL: HTTP is not successful")
except:
Flag = Flag + 1
print("FAIL: HTTP is not successful ")
我的这段代码在python3上运行良好
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。