Объект request: данные запроса полностью

request — это объект, в котором Flask собрал всё про входящий запрос: метод, URL-параметры, тело, заголовки, файлы, куки. Один объект — весь запрос.
request доступен внутри любой view-функции как «глобальный» объект, но это контекстная переменная: для каждого запроса Flask подставляет свой экземпляр. Снаружи запроса обращение к request — ошибка.

В прошлом уроке мы читали request.form. На деле в request лежит гораздо больше. Это единая точка доступа ко всему, что прислал клиент. Разберём ключевые атрибуты — они покрывают 95% задач.

АтрибутЧто содержит
request.methodметод: GET, POST, ...
request.argsпараметры строки запроса (?q=flask)
request.formполя HTML-формы (POST)
request.jsonтело как JSON (для API)
request.filesзагруженные файлы
request.headersHTTP-заголовки
request.cookiesкуки клиента
from flask import request

@app.route("/search")
def search():
    q = request.args.get("q", "")
    page = request.args.get("page", 1, type=int)
    return f"Ищем '{q}', страница {page}"

Обрати внимание на type=int в .get() — Flask сам приведёт строку из URL к числу, а при ошибке вернёт дефолт. Для API читают request.get_json(), для загрузок — request.files["avatar"].

Контекст запроса — одна из тех концепций, что отличает «копипастера» от понимающего разработчика. Знание, что request — это прокси на верхушку стека, объясняет сразу множество ошибок: почему request недоступен в фоновом потоке, почему его нельзя сохранять между запросами, почему в тестах нужен test_request_context. Тот же механизм лежит под объектами session и g, и под объектом current_app. Раз поняв идею контекста, ты перестаёшь воспринимать эти «глобальные» объекты как магию и начинаешь правильно их использовать. И ещё принцип безопасности: всё, что приходит в request, — это вход от пользователя, потенциально враждебный; валидируй и приводи типы, никогда не доверяй структуре входных данных вслепую.

Как работает под капотом

request — это «контекстно-локальный» объект (proxy). Откуда он знает, какой именно запрос обслуживать, если он один на весь модуль? Flask на входе каждого запроса кладёт реальный объект в стек контекста запроса, а request — лишь указатель на верхушку стека. Поэтому в каждом обработчике request свой, а вне запроса стек пуст и обращение падает.

  Запрос A приходит ─▶ push(RequestA) в стек контекста
       view читает request ──▶ верхушка стека = RequestA
  Запрос A завершён ─▶ pop()

  Запрос B приходит ─▶ push(RequestB)
       view читает request ──▶ теперь это RequestB

Смоделируем такой контекстный стек обычным Python, чтобы понять, почему «глобальный» request на самом деле разный для каждого запроса.

_stack = []

class RequestProxy:
    def __getattr__(self, name):
        if not _stack:
            raise RuntimeError("Working outside of request context")
        return getattr(_stack[-1], name)

class Req:
    def __init__(self, path): self.path = path

request = RequestProxy()

def handle(path):
    _stack.append(Req(path))          # push контекста
    try:
        print("view видит путь:", request.path)
    finally:
        _stack.pop()                  # pop после ответа

handle("/a")
handle("/b")
try:
    request.path                      # вне запроса
except RuntimeError as e:
    print("вне контекста:", e)

Запусти: один и тот же request внутри разных запросов указывает на разные объекты, а снаружи кидает ошибку. Это и есть «магия» контекста запроса в Flask.

Частые ошибки

  • Обращаться к request вне запроса. Например в фоновом потоке — «working outside of request context».
  • Путать args и form. args — из URL (?...), form — из тела POST.
  • Доверять request.json без проверки. Если тело не JSON, get_json вернёт None — проверяй.

Best practices

  • Читай значения с дефолтом и type=, не предполагай формат входа.
  • Для API используй get_json(silent=True) и валидируй структуру.
  • Никогда не доверяй данным из request — это вход от пользователя, валидируй всё.

Что запомнить

  • request — единый объект со всеми данными входящего запроса.
  • Ключевые атрибуты: method, args, form, json, files, headers, cookies.
  • request — контекстно-локальный прокси: для каждого запроса свой экземпляр.
  • Вне контекста запроса обращение к request вызывает ошибку.

Итог: request — единый объект со всеми данными запроса, а его «глобальность» обеспечена контекстным стеком: для каждого запроса свой экземпляр. Дальше — как формировать ответы и редиректы.

Проверьте себя
1. В чём разница между request.args и request.form?
AЭто одно и то же
Bargs — параметры URL (?q=...), form — поля POST-тела
Cargs для GET, form для PUT
Dform содержит заголовки
2. Почему 'глобальный' request разный для каждого запроса?
AFlask копирует код view
Brequest — прокси на верхушку контекстного стека запроса
CКаждый запрос создаёт новый модуль
DЭто случайность