Запрос и ответ во Flask
Ядро веб-приложения — это «получение запросов и возврат ответов». В этой главе подробно объясняется, как читать данные запроса и создавать различные типы ответов в Flask.
Все примеры можно напрямую запустить и проверить на сервере разработки.
Объект запроса — request
Flask предоставляет всю информацию о запросе через глобальный прокси-объект.requestПредоставляется вся информация о запросе.
Хотя это «глобальный» объект, внутри Flask использует изоляцию потоков, чтобы каждый запрос получал собственные данные.
Пример
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При чтении он работает как словарь:
Пример
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:
Пример
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, чтобы получить разобранные данные:
Пример
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()Убедитесь, что имя файла безопасно:
Пример
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。
Пример
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"]
Возврат кортежа — управление кодом состояния и заголовками ответа
Формат кортежа очень практичен и имеет три формы:
Пример
@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:
Пример
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:
Пример
@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():
Пример
@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" |