Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 什么会导致响应主体被切断(客户端)?_Python_Json_Sockets_Response - Fatal编程技术网

Python 什么会导致响应主体被切断(客户端)?

Python 什么会导致响应主体被切断(客户端)?,python,json,sockets,response,Python,Json,Sockets,Response,我正在为一个活动代码生成器编写一个python语言插件,该生成器调用我们的RESTAPI。在多次尝试使用requests库和之后,我选择使用低级别的socket和ssl模块,到目前为止,这些模块工作得很好。我使用一种非常粗糙的方法来解析响应;对于正文中相当短的响应,这很好,但我现在尝试检索更大的json对象(用户列表)。响应被切断如下(注意:为了简洁起见,我删除了几个用户条目): {“页面开始”:1,“总计”:5,“用户列表”:[{“用户ID”:“吉姆·莫里森”,“名字”:“吉姆”,“姓氏”:“


我正在为一个活动代码生成器编写一个python语言插件,该生成器调用我们的RESTAPI。在多次尝试使用requests库和之后,我选择使用低级别的socket和ssl模块,到目前为止,这些模块工作得很好。我使用一种非常粗糙的方法来解析响应;对于正文中相当短的响应,这很好,但我现在尝试检索更大的json对象(用户列表)。响应被切断如下(注意:为了简洁起见,我删除了几个用户条目):
{“页面开始”:1,“总计”:5,“用户列表”:[{“用户ID”:“吉姆·莫里森”,“名字”:“吉姆”,“姓氏”:“莫里森”,“语言”:“英语”,“时区”:(GMT+5:30)钦奈,加尔各答,孟买,新德里”,“货币”:“美元”,“角色”:

之后应该会有更多的用户,并且响应主体位于控制台中的一行上

下面是我用来从Rest API服务器请求用户列表的代码:

import socket, ssl, json

host = self.WrmlClientSession.api_host
port = 8443
pem_file = "<pem file>"

url = self.WrmlClientSession.buildURI(host, port, '<root path>')

#Create the header
http_header = 'GET {0} HTTP/1.1\n\n'
req = http_header.format(url)

#Socket configuration and connection execution
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
conn = ssl.wrap_socket(sock, ca_certs = pem_file)
conn.connect((host, port))
conn.send(req)

response = conn.recv()
(headers, body) = response.split("\r\n\r\n")

#Here I would convert the body into a json object, but because the response is 
#cut off, it cannot be properly decoded.  
print(response) 
导入套接字、ssl、json
host=self.WrmlClientSession.api\u主机
端口=8443
pem_文件=“”
url=self.WrmlClientSession.buildURI(主机,端口“”)
#创建标题
http_头='GET{0}http/1.1\n\n'
req=http_头文件格式(url)
#套接字配置和连接执行
sock=socket.socket(socket.AF\u INET,socket.sock\u流)
conn=ssl.wrap\u套接字(sock,ca\u certs=pem\u文件)
连接((主机、端口))
连接发送(请求)
响应=连接记录()
(标题,正文)=响应。拆分(“\r\n\r\n”)
#这里我将把主体转换成json对象,但因为响应是
#如果被切断,则无法正确解码。
打印(答复)
对此问题的任何见解都将不胜感激


编辑:我忘了提到我调试了服务器端的响应,一切都很正常。

你不能假设你可以直接调用
recv()
一次并获取所有数据,因为TCP连接只会缓冲有限的数据量。此外,您没有解析任何标头以确定所需的正文大小。您可以使用非阻塞套接字并一直读取,直到它阻塞为止,这将主要起作用,但根本不可靠,实践也很糟糕,因此我不打算继续我想把它记录在这里

HTTP有方法指示正文的大小,正是出于这个原因,如果您希望代码可靠,正确的方法是使用它们。有两件事需要寻找。首先,如果HTTP响应具有
内容长度
,则表明响应正文中会出现多少字节-您需要继续读取第二个选项是服务器可能会向您发送一个使用的响应-它通过包含一个
传输编码
头来表示这一点,该头的值将包含文本
分块
。我不会在这里讨论分块编码,请阅读详细信息。本质上,正文包含每个“分块”的小头表示该数据块大小的数据。在这种情况下,您必须不断读取数据块,直到得到一个空的数据块,该数据块表示响应结束。当服务器开始发送响应正文时,不知道响应正文的大小时,使用此方法代替
内容长度

一个服务器通常不会同时使用<代码>内容长度和块编码,但是没有什么可以真正阻止它,所以这也是一个需要考虑的问题。如果你只需要与一个特定的服务器进行互操作,那么你可以只告诉它做了什么,并用它来做,但是要知道你会使你的代码变得不易携带和更脆弱。o未来的变化

请注意,在使用这些标头时,您仍然需要在循环中读取,因为任何给定的读取操作都可能返回不完整的数据-TCP被设计为在读取应用程序开始清空缓冲区之前停止发送数据,因此这不是您可以解决的问题。还请注意,每次读取甚至可能不包含完整的数据块,因此您需要跟踪当前区块的大小和已看到的区块数量的状态。只有在看到前一个区块标头指定的字节数时,您才知道要读取下一个区块标头

当然,如果你使用任何一个Python的HTTP库,你就不必担心了。作为一个必须实现一个相当完整的HTTP/1.1客户端的人来说,你真的想让别人做它,如果你可能的话-有相当多的棘手的角落案例需要考虑,你的简单代码就可以了。在很多情况下都会失败。如果

请求
对您不起作用,您是否尝试过任何标准的Python库?对于更高级别的接口,有和,并提供了一种较低级别的方法,您可能会发现它允许您解决一些问题

请记住,如果您真的需要修复问题,您可以随时修改其中的代码(当然,在复制到您的本地存储库之后),或者可能只是导入它们并在中对更改进行修补。但是,您必须非常清楚,这是库中的一个问题,而不仅仅是错误地使用了它

如果你真的想实现一个HTTP客户机,那很好,但是要知道这比看起来要难

最后,我一直使用SSL套接字的方法,而不是使用
recv()
——我希望它们是等效的,但是如果仍然存在问题,您可能希望尝试一下