Обработка данных запроса
Самое важное правило веб-разработки — «Не доверяйте пользователю». Это особенно верно для данных входящих запросов на потоке ввода. С WSGI это на самом деле немного сложнее, чем вы ожидаете. Поэтому Werkzeug обертывает поток запроса, чтобы избавить вас от наиболее распространённых проблем с ним.
Отсутствие маркера EOF в потоке ввода
Поток ввода не имеет маркера конца файла. Если вы вызовете метод read() в потоке wsgi.input, ваше приложение зависнет на серверах, соответствующих стандарту. Однако это сделано намеренно, хотя и неудобно. Werkzeug решает эту проблему, обернув поток ввода в специальный LimitedStream. Поток ввода доступен в объектах запроса как stream. Он либо пустой поток (если данные формы были обработаны), либо ограниченный поток с содержимым потока ввода.
Когда Werkzeug выполняет обработку?
Werkzeug обрабатывает входящие данные в следующих ситуациях:
- вы обращаетесь к
form,files, илиstream, а метод запроса былPOSTилиPUT. - если вы вызываете
parse_form_data().
Эти вызовы не взаимозаменяемы. Если вы вызываете parse_form_data(), вы не должны использовать объект запроса или, по крайней мере, не атрибуты, которые запускают процесс обработки.
Это также верно, если вы читаете из потока wsgi.input до обработки.
Общее правило: Оставьте поток ввода WSGI в покое. Особенно в средах WSGI-сред. Используйте либо функции обработки, либо объект запроса. Не смешивайте несколько библиотек WSGI для обработки данных формы или чего-либо еще, что работает с потоком ввода.
Как происходит обработка?
Стандартное поведение обработки Werkzeug обрабатывает три случая:
- Тип содержимого ввода был
multipart/form-data. В этой ситуацииstreamбудет пустым, аformбудет содержать обычные данныеPOST/PUT,filesбудет содержать загруженные файлы в качестве объектовFileStorage. - Тип содержимого ввода был
application/x-www-form-urlencoded. Тогдаstreamбудет пустым, аformбудет содержать обычные данныеPOST/PUT, аfilesбудет пустым. - Тип содержимого ввода ни тот, ни другой,
streamуказывает наLimitedStreamс данными ввода для дальнейшей обработки.
Особое замечание по методу get_data: Вызов этого метода загружает все данные запроса в память. Это безопасно только в том случае, если max_content_length установлено. Также вы можете либо прочитать поток, либо вызвать get_data().
Ограничение данных запроса
Чтобы избежать атак DDOS, вы можете установить максимальный размер принимаемого содержимого и размеров полей запроса. Класс BaseRequest имеет два атрибута для этого: max_content_length и max_form_memory_size.
Первый можно использовать для ограничения общего размера содержимого. Например, установив его в 1024 * 1024 * 16, запрос не будет принимать более 16 МБ переданных данных.
Поскольку некоторые данные нельзя переместить на жесткий диск (обычные данные POST), а временные файлы можно, существует второе ограничение, которое можно установить. max_form_memory_size ограничивает размер POST переданных данных формы. Установив его в 1024 * 1024 * 2, вы можете убедиться, что все хранящиеся в памяти поля не превышают 2 МБ.
Однако это не влияет на хранящиеся в памяти файлы, если используемый stream_factory возвращает файл в памяти.
Как расширить обработку?
Современные веб-приложения передают намного больше, чем данные multipart form data или url encoded data. Чтобы расширить возможности, подклассифицируйте BaseRequest или Request и добавьте или расширьте методы.
Уже существует миксин, который предоставляет обработку JSON:
from werkzeug.wrappers import Request
from werkzeug.wrappers.json import JSONMixin
class JSONRequest(JSONMixin, Request):
pass
Базовая реализация выглядит так:
from werkzeug.utils import cached_property
from werkzeug.wrappers import Request
import simplejson as json
class JSONRequest(Request):
@cached_property
def json(self):
if self.mimetype == "application/json":
return json.loads(self.data)
© 2007–2020 Pallets
Licensed under the BSD 3-clause License.
https://werkzeug.palletsprojects.com/en/1.0.x/request_data/