在发送实际响应之前发送请求的间歇状态
Send intermittent status of request before sending actual response
我有一个服务器,它需要几分钟来处理一个特定的请求然后响应它。
客户端必须继续等待响应,而不知道它何时会完成。
有没有办法让客户知道处理状态? (比如完成了 50%,完成了 80%),客户端无需轮询状态。
在不使用任何更新技术(websockets、webpush/http2、...)的情况下,我以前使用过简化的 Pushlet 或 用于 HTTP 1.1 和各种 javascript 或自己的客户端实现的长轮询 解决方案。如果我的解决方案不适合您的用例,您可以随时 google 这两个名称以获取更多可能的方法。
客户
发送请求,读取 17 个字节(初始 http 响应),然后一次读取 2 个字节以获取处理状态。
服务器
发送有效的 HTTP 响应,并在请求过程中发送 2 个字节的完成百分比,直到最后 2 个字节为 "ok" 并关闭连接。
更新:示例 uwsgi server.py
from time import sleep
def application(env, start_response):
start_response('200 OK', [])
def working():
yield b'00'
sleep(1)
yield b'36'
sleep(1)
yield b'ok'
return working()
更新:示例请求 client.py
import requests
response = requests.get('http://localhost:8080/', stream=True)
for r in response.iter_content(chunk_size=2):
print(r)
示例服务器(仅用于测试:)
import socket
from time import sleep
HOST, PORT = '', 8888
listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
listen_socket.bind((HOST, PORT))
listen_socket.listen(1)
while True:
client_connection, client_address = listen_socket.accept()
request = client_connection.recv(1024)
client_connection.send('HTTP/1.1 200 OK\n\n')
client_connection.send('00') # 0%
sleep(2) # Your work is done here
client_connection.send('36') # 36%
sleep(2) # Your work is done here
client_connection.sendall('ok') # done
client_connection.close()
如果最后 2 个字节不是 "ok",请以其他方式处理错误。这不是漂亮的 HTTP 状态代码合规性,而是多年前对我有用的解决方法。
telnet 客户端示例
$ telnet localhost 8888
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET / HTTP/1.1
HTTP/1.1 200 OK
0036okConnection closed by foreign host.
使用分块传输编码,这是传输未知长度流的标准技术。
参见:Wikipedia - Chunked Transfer Encoding
这里有一个 python 服务器实现,可作为 GitHub 上的要点:
它使用标准库模块使用分块传输编码发送内容
在客户端,如果服务器通知了分块传输编码,你只需要:
import requests
response = requests.get('http://server.fqdn:port/', stream=True)
for r in response.iter_content(chunk_size=None):
print(r)
chunk_size=None
,因为块是动态的,将由块传输语义的简单约定中的信息确定。
参见:http://docs.python-requests.org/en/master/user/advanced/#chunk-encoded-requests
当您在响应 r
的内容中看到例如 100
时,您知道下一个块将是处理 100
后的实际内容。
此答案可能对您的特定情况没有帮助,但在其他情况下可能会有所帮助。
HTTP协议支持informational (1xx) responses:
indicates an interim
response for communicating connection status or request progress
prior to completing the requested action and sending a final
response
甚至还有一个状态代码正好适合您的用例,102 (Processing):
interim response used to
inform the client that the server has accepted the complete request,
but has not yet completed it
状态代码 102 由于缺少实现而从该标准的后续版本中删除,但它仍然是 registered 并且可以使用。
因此,它可能看起来像这样(HTTP/2 具有等效的二进制形式):
HTTP/1.1 102 Processing
Progress: 50%
HTTP/1.1 102 Processing
Progress: 80%
HTTP/1.1 200 OK
Date: Sat, 05 Aug 2017 11:53:14 GMT
Content-Type: text/plain
All done!
不幸的是,这没有得到广泛支持。特别是,WSGI 不提供发送任意 1xx 响应的方法。客户端支持 1xx 响应,因为它们 需要解析和容忍它们 ,但它们通常不提供对它们的编程访问:在本例中,Progress
header 对客户端应用程序不可用。
但是,1xx 响应可能仍然有用(如果服务器可以发送它们),因为它们具有 重置客户端套接字读取超时的效果,这是主要的功能之一响应慢的问题。
我有一个服务器,它需要几分钟来处理一个特定的请求然后响应它。
客户端必须继续等待响应,而不知道它何时会完成。
有没有办法让客户知道处理状态? (比如完成了 50%,完成了 80%),客户端无需轮询状态。
在不使用任何更新技术(websockets、webpush/http2、...)的情况下,我以前使用过简化的 Pushlet 或 用于 HTTP 1.1 和各种 javascript 或自己的客户端实现的长轮询 解决方案。如果我的解决方案不适合您的用例,您可以随时 google 这两个名称以获取更多可能的方法。
客户 发送请求,读取 17 个字节(初始 http 响应),然后一次读取 2 个字节以获取处理状态。
服务器 发送有效的 HTTP 响应,并在请求过程中发送 2 个字节的完成百分比,直到最后 2 个字节为 "ok" 并关闭连接。
更新:示例 uwsgi server.py
from time import sleep
def application(env, start_response):
start_response('200 OK', [])
def working():
yield b'00'
sleep(1)
yield b'36'
sleep(1)
yield b'ok'
return working()
更新:示例请求 client.py
import requests
response = requests.get('http://localhost:8080/', stream=True)
for r in response.iter_content(chunk_size=2):
print(r)
示例服务器(仅用于测试:)
import socket
from time import sleep
HOST, PORT = '', 8888
listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
listen_socket.bind((HOST, PORT))
listen_socket.listen(1)
while True:
client_connection, client_address = listen_socket.accept()
request = client_connection.recv(1024)
client_connection.send('HTTP/1.1 200 OK\n\n')
client_connection.send('00') # 0%
sleep(2) # Your work is done here
client_connection.send('36') # 36%
sleep(2) # Your work is done here
client_connection.sendall('ok') # done
client_connection.close()
如果最后 2 个字节不是 "ok",请以其他方式处理错误。这不是漂亮的 HTTP 状态代码合规性,而是多年前对我有用的解决方法。
telnet 客户端示例
$ telnet localhost 8888
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET / HTTP/1.1
HTTP/1.1 200 OK
0036okConnection closed by foreign host.
使用分块传输编码,这是传输未知长度流的标准技术。
参见:Wikipedia - Chunked Transfer Encoding
这里有一个 python 服务器实现,可作为 GitHub 上的要点:
它使用标准库模块使用分块传输编码发送内容
在客户端,如果服务器通知了分块传输编码,你只需要:
import requests
response = requests.get('http://server.fqdn:port/', stream=True)
for r in response.iter_content(chunk_size=None):
print(r)
chunk_size=None
,因为块是动态的,将由块传输语义的简单约定中的信息确定。
参见:http://docs.python-requests.org/en/master/user/advanced/#chunk-encoded-requests
当您在响应 r
的内容中看到例如 100
时,您知道下一个块将是处理 100
后的实际内容。
此答案可能对您的特定情况没有帮助,但在其他情况下可能会有所帮助。
HTTP协议支持informational (1xx) responses:
indicates an interim response for communicating connection status or request progress prior to completing the requested action and sending a final response
甚至还有一个状态代码正好适合您的用例,102 (Processing):
interim response used to inform the client that the server has accepted the complete request, but has not yet completed it
状态代码 102 由于缺少实现而从该标准的后续版本中删除,但它仍然是 registered 并且可以使用。
因此,它可能看起来像这样(HTTP/2 具有等效的二进制形式):
HTTP/1.1 102 Processing
Progress: 50%
HTTP/1.1 102 Processing
Progress: 80%
HTTP/1.1 200 OK
Date: Sat, 05 Aug 2017 11:53:14 GMT
Content-Type: text/plain
All done!
不幸的是,这没有得到广泛支持。特别是,WSGI 不提供发送任意 1xx 响应的方法。客户端支持 1xx 响应,因为它们 需要解析和容忍它们 ,但它们通常不提供对它们的编程访问:在本例中,Progress
header 对客户端应用程序不可用。
但是,1xx 响应可能仍然有用(如果服务器可以发送它们),因为它们具有 重置客户端套接字读取超时的效果,这是主要的功能之一响应慢的问题。