Запрос и ответ во Flask

Ядро веб-приложения — это «получение запросов и возврат ответов». В этой главе подробно объясняется, как читать данные запроса и создавать различные типы ответов в Flask.

Все примеры можно напрямую запустить и проверить на сервере разработки.


Объект запроса — request

Flask предоставляет всю информацию о запросе через глобальный прокси-объект.requestПредоставляется вся информация о запросе.

Хотя это «глобальный» объект, внутри Flask использует изоляцию потоков, чтобы каждый запрос получал собственные данные.

Пример

# Импортируем request — потокобезопасный прокси-объект
from flask import Flask, request

app = Flask(__name__)

@app.route("/debug")
def debug():
    # Вывод различной информации о запросе для лучшего понимания объекта запроса
    return f"""
<h1>Информация для отладки запроса</h1>
    <ul>
<li>Метод: {request.method}</li>
<li>Путь: {request.path}</li>
<li>Полный URL: {request.url}</li>
<li>Хост: {request.host}</li>
<li>IP клиента: {request.remote_addr}</li>
        <li>User-Agent:{request.headers.get('User-Agent')}</li>
    </ul>
    """

Посетитеhttp://127.0.0.1:5000/debug?foo=barВы можете увидеть подробную информацию о запросе.


Получение параметров запроса — request.args

В URL?Параметры после него называются параметрами запроса (Query String).

Использованиеrequest.argsПри чтении он работает как словарь:

Пример

@app.route("/search")
def search():
    # request.args.get() безопасно получает параметр, возвращает None, когда ключ не существует
    keyword = request.args.get("keyword", "")  # Получить параметр запроса
    page = request.args.get("page", "1")       # Получить номер страницы, по умолчанию 1
    return f"""
<h1>Результаты поиска</h1>
<p>Ключевое слово: {keyword}</p>
<p>Страница: {page}</p>
    """

# Тест: /search?keyword=flask&page=2
# Тест: /search?keyword=EXAMPLE

Рекомендуется.get()Используйте метод вместо прямого доступа по индексу.request.args["key"], потому что последний выбрасывает исключение, когда ключ не существует.KeyError, что приводит к странице ошибки 400.


Получение данных формы — request.form

Чтобы обработать данные формы, отправленные POST-запросами, используйтеrequest.form:

Пример

@app.route("/register", methods=["GET", "POST"])
def register():
    if request.method == "POST":
        # Используйте значение поля name="username" в форме
        username = request.form.get("username", "")
        password = request.form.get("password", "")

        if not username or not password:
            return "<h1>Ошибка</h1><p>Имя пользователя и пароль не могут быть пустыми</p>", 400

        return f"<h1>Регистрация успешна</h1><p>Добро пожаловать, {username}, в EXAMPLE!</p>"

    # Отобразить форму регистрации при GET-запросе
    return """
<h1>Регистрация</h1>
    <form method="post">
<p>Имя пользователя: <input type="text" name="username"></p>
<p>Пароль: <input type="password" name="password"></p>
<p><input type="submit" value="Зарегистрироваться"></p>
    </form>
    """

Примечание: на HTML-странице, которая обрабатывает форму,<form>необходимо установитьmethod="post", иначе данные будут отправлены через строку запроса URL (метод GET), и конфиденциальная информация будет раскрыта в URL.


Получение данных JSON — request.json

В современной веб-разработке JSON — самый распространённый формат данных.

Когда клиент отправляетContent-Type: application/jsonзапрос, используйтеrequest.json, чтобы получить разобранные данные:

Пример

@app.post("/api/user")
def create_user():
    # request.json возвращает данные JSON, уже разобранные в Python dict
    data = request.json  # Например, клиент отправляет {"name": "example", "email": "[email protected]"}

    # Безопасно получить поле
    name = data.get("name", "Unknown")
    email = data.get("email", "Not provided")

    # Возвращайте dict напрямую, Flask автоматически преобразует его в JSON-ответ
    return {
        "message": "Пользователь успешно создан",
        "name": name,
        "email": email
    }

Можно использоватьcurlили Postman для тестирования:

$ curl -X POST http://127.0.0.1:5000/api/user \
  -H "Content-Type: application/json" \
  -d '{"name": "example", "email": "[email protected]"}'
{
  "message": "用户创建成功",
  "name": "example",
  "email": "[email protected]"
}

Загрузка файлов

Используйте это для обработки загруженных файлов:request.files, в сочетании с предоставляемой Werkzeugsecure_filename()Убедитесь, что имя файла безопасно:

Пример

import os
from werkzeug.utils import secure_filename  # Фильтрация опасных символов в имени файла

# Настройте каталог загрузки (в реальном проекте это должно считываться из конфигурации)
UPLOAD_DIR = "uploads"

@app.route("/upload", methods=["GET", "POST"])
def upload_file():
    if request.method == "POST":
        # Проверить, был ли загружен файл
        if "file" not in request.files:
            return "Файл не выбран", 400

        file = request.files["file"]

        # Возможно, пользователь отправил пустую форму (файл не выбран)
        if file.filename == "":
            return "Имя файла пустое", 400

        # secure_filename отфильтровывает опасные символы, такие как обход пути
        # Например, "../../etc/passwd" будет преобразован в "etc_passwd"
        filename = secure_filename(file.filename)

        # Убедитесь, что каталог загрузки существует
        os.makedirs(UPLOAD_DIR, exist_ok=True)

        # Сохранить файл
        file.save(os.path.join(UPLOAD_DIR, filename))
        return fФайл {filename} успешно загружен

    # GET-запрос показывает форму загрузки
    return """
<h1>Загрузить файл</h1>
    <form method="post" enctype="multipart/form-data">
        <p><input type="file" name="file"></p>
<p><input type="submit" value="Загрузить"></p>
    </form>
    """

Если форма содержит поле загрузки файла,<form>Необходимо указатьenctype="multipart/form-data", иначе данные файла не будут отправлены браузером.


Полное руководство по типам ответов

Функции представления могут возвращать данные разных типов, и Flask автоматически преобразует их в соответствующие HTTP-ответы.

Понимание этого правила преобразования — ключ к освоению Flask.

Возврат строки

Возвращаемая строка служит телом HTML-ответа, с кодом состояния по умолчанию 200 и Content-Type:text/html。

Вернуть словарь или список (JSON)

Автоматически вызываетсяjsonify()преобразует в JSON-ответ, с Content-Type, установленным вapplication/json。

Пример

@app.get("/api/posts")
def get_posts():
    # Вернуть dict, Flask автоматически преобразует в JSON
    return {
        "status": "ok",
        "data": [
            {"id": 1, "title": Учебник по Flask},
            {"id": 2, "title": Проектирование RESTful API},
        ]
    }

@app.get("/api/tags")
def get_tags():
    # Вернуть list, Flask автоматически преобразует в JSON
    return ["Python", "Flask", Веб-разработка, "EXAMPLE"]

Возврат кортежа — управление кодом состояния и заголовками ответа

Формат кортежа очень практичен и имеет три формы:

Пример

# Форма 1: (body, status_code)
@app.get("/not-found")
def not_found():
    return <h1>Страница не найдена</h1>, 404

# Форма 2: (body, headers_dict)
@app.get("/custom-header")
def custom_header():
    return "OK", {"X-Custom-Header": "example"}

# Форма 3: (body, status_code, headers_dict)
@app.post("/api/login")
def api_login():
    # Вернуть токен и пользовательский код состояния
    return {"token": "abc123", "user": "example"}, 201, {"X-RateLimit": "100"}

Redirect

Использованиеredirect()Функция перенаправляет пользователя на другой URL:

Пример

from flask import Flask, redirect, url_for

app = Flask(__name__)

@app.route("/")
def index():
    # Перенаправление на страницу входа при посещении главной страницы
    return redirect(url_for("login"))

@app.route("/login")
def login():
    return <h1>Пожалуйста, сначала войдите</h1>

@app.route("/old-page")
def old_page():
    # Старая страница навсегда перемещена на новую страницу, используйте код состояния 301
    return redirect(url_for("new_page"), code=301)

@app.route("/new-page")
def new_page():
    return <h1>Это новая страница</h1>

Код состояния перенаправления по умолчанию —303 See Other, подходит для перенаправления после отправки формы (шаблон PRG).

Для сценариев постоянной миграции используйтеcode=301。


Завершение запроса — abort

Использованиеabort()Немедленно завершите текущий запрос и верните ошибку HTTP:

Пример

from flask import abort

@app.route("/post/<int:post_id>")
def view_post(post_id):
    # Предположим, что идентификаторы статей только 1-100
    if post_id < 1 or post_id > 100:
        # Немедленно вернуть 404, последующий код не выполнится
        abort(404)

    return f"<h1>Статья #{post_id}</h1>"

@app.route("/admin")
def admin():
    # Вернуть 403 при несанкционированном доступе
    abort(403, description=У вас нет разрешения на доступ к этой странице)

make_response — вручную управлять ответом

Когда нужно вручную установить куки или настроить заголовки ответа, используйтеmake_response():

Пример

from flask import make_response

@app.route("/set-cookie")
def set_cookie():
    # make_response оборачивает возвращаемое значение функции представления в объект Response
    resp = make_response(<h1>Куки установлены</h1>)

    # Установить куки в объекте Response
    resp.set_cookie("theme", "dark", max_age=60*60*24)  # Действует 24 часа
    resp.set_cookie("lang", "zh-CN")

    # Вы также можете настроить заголовки ответа
    resp.headers["X-Powered-By"] = "EXAMPLE-Flask"

    return resp

Краткая справочная таблица общих атрибутов запроса

Свойство Type Описание Пример значения
request.method str Метод HTTP-запроса "GET", "POST"
request.path str Путь URL (без доменного имени) "/search"
request.args MultiDict Параметры строки запроса URL ?keyword=flask&page=1
request.form MultiDict Данные POST-формы username=admin
request.json dict или None Тело JSON-запроса (разобрано) {"name": "example"}
request.files FileMultiDict Загруженный файл request.files["avatar"]
request.headers Headers Заголовки запроса request.headers["User-Agent"]
request.cookies dict Cookie, отправленный клиентом request.cookies.get("theme")
request.remote_addr str IP-адрес клиента "127.0.0.1"
Другие расширения