В Heroku, использующем Gunicorn и Flask с ограничением полезной нагрузки, heroku дает 503 вместо 413, когда я намеренно поднимаю 413 с высокой полезной нагрузкой. - PullRequest
0 голосов
/ 27 сентября 2019

Добрый день!

Обычно я нахожу все решения здесь в stackoverflow, но на этот раз я столкнулся с какой-то странной ошибкой, которую никогда не видел, и, вероятно, я сделал это сам с недостаточным знанием.

Пожалуйста, прочитайте до конца, чтобы понять мою проблему и то, что я нашел до сих пор:)

Недавно я создал API, использующий Flask, который получает данные json в качестве полезной нагрузки для выполнения.Приходите по волшебству и возвращаете результат пользователю.У меня есть точка проверки в моем коде, которая проверяет, не является ли полезная нагрузка слишком большой, например, не более, чем, скажем, 256 байт (для целей тестирования).

Все работает локально и в heroku, пока полезная нагрузка ниже предела,Но в Heroku, когда я превышаю предел, например, в 162 раза, то вместо поднятой ошибки 413 я получаю 503 с кодом h18.

Так, например, мой код, который выполняет проверку content_length, выглядит примерно так:

from flask import request, make_response, jsonify

from my app.api import bp


@bp.route('/magic', methods=['POST'])
@token_auth.login_required
def magic():
    content_length = request.content_length

    if int(content_length) > allowed_clength:
        response = make_response(jsonify({
            'error': 'Too large payload in a single request!',
            'expected_content_length': f'bytes: {allowed_clength}',
            'received_content_length': f'bytes: {content_length}'
        }), 413)
        return response
    else:
        print('magic goes here')

Поэтому, когда я отправляю payload.content_length выше допустимого предела (например, 42062 байта), ноне превышая огромные накладные расходы, я получаю ожидаемый ответ от моего приложения в heroku:

{
    "error": "Too large payload in a single request!",
    "expected_content_length": "bytes: 256",
    "received_content_length": "bytes: 42062"
}

Но когда я отправляю с почтальоном запрос к моей /api/magic конечной точке с огромной полезной нагрузкой, которая content_length превышает allowed_clength большезатем, как например, 172 (или 44271 байт) раза, я получаю следующую ошибку в логах heroku:

2019-09-27T05:03:15.959932+00:00 app[web.1]: <some-ip> - - [27/Sep/2019:05:03:15 +0000] "POST /api/magic HTTP/1.1" 413 131 "-" "PostmanRuntime/7.6.0"
2019-09-27T05:03:15.984553+00:00 heroku[router]: sock=backend at=error code=H18 desc="Server Request Interrupted" method=POST path="/api/magic" host=my-host request_id=<some-request-id> fwd="my-ip" dyno=web.1 connect=0ms service=44ms status=503 bytes=306 protocol=https

И в почтальоне я получаю следующую ошибку:

<!DOCTYPE html>
<html>
    <head>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta charset="utf-8">
        <title>Application Error</title>
        <style media="screen">
          html,body,iframe {
            margin: 0;
            padding: 0;
          }
          html,body {
            height: 100%;
            overflow: hidden;
          }
          iframe {
            width: 100%;
            height: 100%;
            border: 0;
          }
        </style>
    </head>
    <body>
        <iframe src="//<heroku-error-age>"></iframe>
    </body>
</html>

Iнашел объяснение кода ошибки в heroku - пример ошибки с nodejs , который говорит, что

Resolution

Ошибка H18 аналогична H13 в том, что оба означают, чтосокет был уничтожен до того, как ответ был завершен.С H13 сокет был подключен, а затем уничтожен без отправки каких-либо данныхH18 означает, что сокет подключен, некоторые данные были отправлены как часть ответа приложением, но затем сокет был разрушен без завершения ответа.

Обычно H18 указывает, что ответ имеет несколько этапов -например, потоковые фрагменты большого ответа - и на одном из этих этапов возникла ошибка.

Чтобы найти ошибку, сначала проверьте журналы на наличие следов стека около H18.Если вы ничего не видите, вам нужно более внимательно посмотреть на обработчики для конкретного запроса, который не выполняется.Регистрация каждого шага ответа, включая заголовок x-request-id, может помочь.

Но это не объясняет мне, почему он действует по-другому только с дополнительными ~ 2000 байтами, я быскажем, что это потому, что в heroku есть некоторые ограничения, например, Heroku говорит, что у них нет предела запроса, хорошо, тогда, может быть, тогда ограничение по времени ожидания запроса, которое по умолчанию составляет 30 секунд в heroku, но при сравнении приведенных выше примеров полезной нагрузки с ожидаемымОшибка 413 A - 42062 of bytes с ответом в 419ms и ошибка 503 (H18) B - 44271 of bytes с временем ответа даже любовника 324ms.

Также я нашел этот вопрос у него похожая проблема, но они используют socketio, а я нет (по крайней мере, я так думаю, потому что я нигде явно не объявил об этом).

Я попытался создать специфически errohandler, который бы ловил 413ошибка, но все еще не удалось ее решить.

Итак, мой вопрос: каковы возможные способы отладки этого странного поведения и его исправления?Потому что в логах heroku я вижу только то, что я написал, в моем локальном env я не могу воспроизвести это, в коде примера я добавил операторы print, которые показывают шаги, поэтому создание response = jsonify({...}) работает только на return responseошибка происходит как я понимаю.

Спасибо за терпение, все комментарии и помощь!

...