【问题标题】:How to send multiple responses from one request in Flask?如何从 Flask 中的一个请求发送多个响应?
【发布时间】:2020-02-04 21:02:34
【问题描述】:

我正在使用 Flask 对服务进行原型设计,该服务将接收一个可能匹配多个目标的 POST 请求,每个目标都会生成一个响应以发送回发送者。这些响应不应组合成一个响应。适当地,Flask 似乎对一个请求执行一个响应。有没有办法根据需要[手动]生成和发送我的回复?

使用简单的 Flask hello-world 演示作为基础,我正在寻找的解决方案可能像这样简单,如果存在的话:

@app.route('/', methods=['POST']
def receive():
   if request_matches_more_than_one_handler(request):
      # Let's say we want a total of 3 responses
      # Generate and send 2 responses here. How?
   # Now rely on flask to send the third response
   return '200 OK...'

我无法在路径上调度。

感谢您的任何意见!

【问题讨论】:

  • 您不能将您的“响应”包装在一个 json 对象中吗?在我看来,这并不是 HTTP 一开始就应该如何工作的。刚才想到的另一件事是,如果有任何数据剩余,您可以在第一个响应中返回,而要求第一个响应的人知道发送第二个或第三个响应的请求……有点像分页解决方案?
  • HTTP 正是您不想使用的。另一种方法是在这种情况下使用 websocket。

标签: python-3.x flask wsgi dispatch


【解决方案1】:

由于 HTTP 规范,这在形式上是不可能的,但这里有一个棘手的解决方法。你可以使用stream:

烧瓶服务器

from flask import Flask, stream_with_context, request, jsonify, Response
from time import sleep
import json

app = Flask(__name__)


def destination1(param):
  sleep(5)
  return {"data": f"{param} from destination1"}


def destination2(param):
  sleep(5)
  return {"data": f"{param} from destination2"}


def destination3(param):
  sleep(5)
  return {"data": f"{param} from destination3"}


@app.route('/destination1', methods=['POST'])
def destination1_route():
  return jsonify(destination1(request.json["param"]))


@app.route('/destination2', methods=['POST'])
def destination2_route():
  return jsonify(destination2(request.json["param"]))


@app.route('/destination3', methods=['POST'])
def destination3_route():
  return jsonify(destination3(request.json["param"]))


@app.route('/multi_destination', methods=['POST'])
def streamed_response():

  destinations = request.json["destinations"]

  def generate(destinations):
    i = 0
    last_element_num = len(destinations)-1
    yield '[\n'
    for destination in destinations:
      if i == last_element_num:
        yield json.dumps(eval(f'{destination["name"]}("{destination["param"]}")')) + '\n'
      else:
        yield json.dumps(eval(f'{destination["name"]}("{destination["param"]}")')) + ',\n'
      i += 1
    yield ']'

  return app.response_class(stream_with_context(generate(destinations)), mimetype='application/json')


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000)

请求者

from time import time
import requests

json_data = {
    "destinations": [
        {"name": "destination1", "param": "param1"},
        {"name": "destination2", "param": "param2"},
        {"name": "destination3", "param": "param3"}
    ]
}

start_time = time()
r = requests.post('http://127.0.0.1:8000/multi_destination', json=json_data, timeout=7)
end_time = time()

print('Output:')
print(r.text)

print('HTTP response time:', r.elapsed.total_seconds())
print('Actually elapsed time:', end_time - start_time)

输出

Output:
[
{"data": "param1 from destination1"},
{"data": "param2 from destination2"},
{"data": "param3 from destination3"}
]
HTTP response time: 0.001916
Actually elapsed time: 15.01642894744873

因此,您可以看到总经过时间为 15 秒,但请求超时时间仅为 7 秒。总时间大于超时,因为我们每 5 秒获取一次数据块 (sleep(5))。因此,您可以通过定期发送一些数据来保持连接数小时和数天。

在我的requester 示例中,您必须等待所有数据传输完毕。如果您想从destination1 获得响应并开始处理它而不等待来自destination2 的响应,您可以使用iterable way 进行请求。在这种情况下,您将能够立即处理{"data": "param1 from destination1"}, 行,而无需等待下一个数据。

您也可以查看answer(客户端)以了解如何在下载所有数据时无需等待即可处理流块

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-06-16
    • 1970-01-01
    • 1970-01-01
    • 2017-10-12
    • 1970-01-01
    • 1970-01-01
    • 2020-11-13
    • 1970-01-01
    相关资源
    最近更新 更多