【问题标题】:Batching API requests with flask-restful使用 flask-restful 批处理 API 请求
【发布时间】:2015-05-02 02:13:18
【问题描述】:

我正在使用 flask-restful 构建一个 REST API,我想启用的一件事是能够批量请求资源,类似于 Facebook Graph API 的工作方式:

curl \
    -F 'access_token=…' \
    -F 'batch=[{"method":"GET", "relative_url":"me"},{"method":"GET", "relative_url":"me/friends?limit=50"}]' \
    https://graph.facebook.com

然后返回一个数组,每个请求都通过其状态码和结果解析:

[
    { "code": 200, 
      "headers":[
          { "name": "Content-Type", 
            "value": "text/javascript; charset=UTF-8" }
      ],
      "body": "{\"id\":\"…\"}"},
    { "code": 200,
      "headers":[
          { "name":"Content-Type", 
            "value":"text/javascript; charset=UTF-8"}
      ],
      "body":"{\"data\": [{…}]}}
]

我已经能够通过简单地循环请求并针对我自己的应用程序调用 urlopen 在 flask-restful 中复制这一点。这似乎真的很低效,我不得不认为有更好的方法。是否有更简单和/或更好的方法可以从请求处理程序中对我自己的应用程序发出请求?

【问题讨论】:

    标签: rest flask flask-restful


    【解决方案1】:

    由于您需要返回标头,因此我的建议是您将这些批量请求发送给自己(即将请求发送到localhost),这样响应将与您在进行单独调用时获得的响应一致。

    请考虑,当您的 API 收到批处理请求时,您将需要至少一个空闲的工作人员来处理这些间接请求,而第一个工作人员会阻塞并等待。所以你需要至少有两个工人。即使这样,如果两个批处理请求同时到达并占用您的两个工人,您也可能会陷入僵局。因此,实际上,您需要拥有与您期望同时接收的批处理请求一样多的工作人员,再加上至少一个来处理间接请求。

    从另一方面来看,您将希望并行运行尽可能多的这些间接请求,因为如果它们最终一个接一个地运行,那么使用批处理请求的好处就会丧失。因此,您还需要有足够数量的工作人员来支持并行性。

    老实说,我不认为这是一个很棒的功能。在大多数客户端语言中,并行执行多个请求相当容易,因此您无需提供这是服务器端功能。如果您使用 Javascript,则特别容易,但在 Python、Ruby 等中也很容易。

    【讨论】:

    • 谢谢米格尔。我主要是为 API 的移动应用程序消费者实现它,但是 a)他们也可以非常简单地执行并行请求,并且 b)我认为你是对的,这些好处并不值得。感谢您提供的信息和关于僵局的一点点让我意识到这根本不值得。
    【解决方案2】:

    您可以只使用 Flask 来执行批量提交的单个请求,如下所示。

    批量请求

    [
        {
            "method" : <string:method>,
            "path"   : <string:path>,
            "body"   : <string:body>
        },
        {
            "method" : <string:method>,
            "path"   : <string:path>,
            "body"   : <string:body>
        }
    ]
    

    批量响应

    [
        {
            "status"   : <int:status_code>,
            "response" : <string:response>
        },
        {
            "status"   : <int:status_code>,
            "response" : <string:response>
        }
    ]
    

    示例代码

    def _read_response(response):
        output = StringIO.StringIO()
        try:
            for line in response.response:
                output.write(line)
    
            return output.getvalue()
    
        finally:
            output.close()
    
    @app.route('/batch', methods=['POST'])
    def batch(username):
        """
        Execute multiple requests, submitted as a batch.
    
        :statuscode 207: Multi status
        """
        try:
            requests = json.loads(request.data)
        except ValueError as e:
            abort(400)
    
        responses = []
    
        for index, req in enumerate(requests):
            method = req['method']
            path = req['path']
            body = req.get('body', None)
    
            with app.app_context():
                with app.test_request_context(path, method=method, data=body):
                    try:
                        # Can modify flask.g here without affecting flask.g of the root request for the batch
    
                        # Pre process Request
                        rv = app.preprocess_request()
    
                        if rv is None:
                            # Main Dispatch
                            rv = app.dispatch_request()
    
                    except Exception as e:
                        rv = app.handle_user_exception(e)
    
                    response = app.make_response(rv)
    
                    # Post process Request
                    response = app.process_response(response)
    
            # Response is a Flask response object.
            # _read_response(response) reads response.response and returns a string. If your endpoints return JSON object,
            # this string would be the response as a JSON string.
            responses.append({
                "status": response.status_code,
                "response": _read_response(response)
            })
    
        return make_response(json.dumps(responses), 207, HEADERS)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-12-03
      • 2023-02-09
      • 1970-01-01
      • 1970-01-01
      • 2019-04-05
      • 2014-02-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多