Flask Solicitudes y Respuestas
El núcleo de una aplicación web es «recibir solicitudes y devolver respuestas». Este capítulo explica en detalle cómo leer los datos de solicitud y construir varios tipos de respuestas en Flask.
Todos los ejemplos se pueden ejecutar y verificar directamente en el servidor de desarrollo.
Objeto de solicitud — request
Flask, a través de un objeto proxy global,requestproporciona toda la información de la solicitud.
Aunque es un objeto «global», Flask internamente utiliza un mecanismo de aislamiento de hilos para garantizar que cada solicitud obtenga sus propios datos.
Ejemplo
from flask import Flask, request
app = Flask(__name__)
@app.route("/debug")
def debug():
# Mostrar varias informaciones de la solicitud para ayudar a entender el objeto request
return f"""
<h1>Información de depuración de la solicitud</h1>
<ul>
<li>Método: {request.method}</li>
<li>Ruta: {request.path}</li>
<li>URL completa: {request.url}</li>
<li>Host: {request.host}</li>
<li>IP del cliente: {request.remote_addr}</li>
<li>User-Agent:{request.headers.get('User-Agent')}</li>
</ul>
"""
Accedehttp://127.0.0.1:5000/debug?foo=bary verás la información detallada de la solicitud.

Obtener parámetros de consulta — request.args
En la URL,?los parámetros posteriores se denominan parámetros de consulta (Query String).
Usarequest.argspara leerlos; se comporta como un diccionario:
Ejemplo
def search():
# request.args.get() obtiene parámetros de forma segura; devuelve None si la clave no existe
keyword = request.args.get("keyword", "") # Obtener la palabra clave de búsqueda
page = request.args.get("page", "1") # Obtener el número de página, por defecto 1
return f"""
<h1>Resultados de búsqueda</h1>
<p>Palabra clave: {keyword}</p>
<p>Página: {page}</p>
"""
# Prueba: /search?keyword=flask&page=2
# Prueba: /search?keyword=EJEMPLO
Se recomienda utilizar.get()en lugar de acceder directamente por índice,request.args["key"]porque esto último lanza una excepción cuando la clave no existe,KeyErrorlo que provoca que se devuelva una página de error 400.
Obtener datos de formulario — request.form
Para procesar los datos de formulario enviados mediante una solicitud POST, usarequest.form:
Ejemplo
def register():
if request.method == "POST":
# Usar el valor del campo name="username" del formulario
username = request.form.get("username", "")
password = request.form.get("password", "")
if not username or not password:
return "<h1>Error</h1><p>El nombre de usuario y la contraseña no pueden estar vacíos</p>", 400
return f"<h1>Registro exitoso</h1><p>¡Bienvenido {username} a EJEMPLO!</p>"
# Mostrar el formulario de registro cuando la solicitud es GET
return """
<h1>Registro</h1>
<form method="post">
<p>Usuario: <input type="text" name="username"></p>
<p>Contraseña: <input type="password" name="password"></p>
<p><input type="submit" value="Registrarse"></p>
</form>
"""
Nota: en la página HTML que procesa el formulario,<form>debe configurarsemethod="post", de lo contrario los datos se envían a través de la cadena de consulta de la URL (método GET) y la información sensible queda expuesta en la URL.
Obtener datos JSON — request.json
En el desarrollo web moderno, JSON es el formato de datos más común.
Cuando el cliente envíaContent-Type: application/jsonuna solicitud de este tipo, utilizarequest.jsonpara obtener los datos parseados:
Ejemplo
def create_user():
# request.json devuelve los datos JSON ya convertidos en un dict de Python
data = request.json # Por ejemplo, el cliente envía {"name": "ejemplo", "email": "[email protected]"}
# Obtener los campos de forma segura
name = data.get("name", "Desconocido")
email = data.get("email", "No proporcionado")
# Devolver el dict directamente; Flask lo convierte automáticamente en una respuesta JSON
return {
"message": "Usuario creado correctamente",
"name": name,
"email": email
}
Puedes usarcurlo Postman para probar:
$ curl -X POST http://127.0.0.1:5000/api/user \
-H "Content-Type: application/json" \
-d '{"name": "ejemplo", "email": "[email protected]"}'
{
"message": "用户创建成功",
"name": "ejemplo",
"email": "[email protected]"
}
Subida de archivos
Para procesar los archivos subidos, usarequest.files, junto con el proporcionado por Werkzeugsecure_filename()para garantizar que el nombre de archivo sea seguro:
Ejemplo
from werkzeug.utils import secure_filename # Filtrar caracteres peligrosos del nombre de archivo
# Configurar el directorio de subida (en un proyecto real debería leerse de la configuración)
UPLOAD_DIR = "uploads"
@app.route("/upload", methods=["GET", "POST"])
def upload_file():
if request.method == "POST":
# Comprobar si se ha subido un archivo
if "file" not in request.files:
return "No se seleccionó ningún archivo", 400
file = request.files["file"]
# El usuario puede haber enviado un formulario vacío (sin seleccionar archivo)
if file.filename == "":
return "El nombre de archivo está vacío", 400
# secure_filename filtra caracteres peligrosos como path traversal
# Por ejemplo, "../../etc/passwd" se convierte en "etc_passwd"
filename = secure_filename(file.filename)
# Asegurar que el directorio de subida exista
os.makedirs(UPLOAD_DIR, exist_ok=True)
# Guardar el archivo
file.save(os.path.join(UPLOAD_DIR, filename))
return f"Archivo {filename} subido correctamente"
# Mostrar el formulario de subida cuando la solicitud es GET
return """
<h1>Subir archivo</h1>
<form method="post" enctype="multipart/form-data">
<p><input type="file" name="file"></p>
<p><input type="submit" value="Subir"></p>
</form>
"""
Si el formulario tiene un campo de subida de archivos,<form>la etiqueta debe configurarseenctype="multipart/form-data", de lo contrario el navegador no enviará los datos del archivo.
Guía completa de tipos de respuesta
Las funciones de vista pueden devolver varios tipos de datos; Flask los convierte automáticamente en respuestas HTTP adecuadas.
Entender esta regla de conversión es clave para dominar Flask.
Devolver una cadena
La cadena devuelta se usa como cuerpo de la respuesta HTML; el código de estado por defecto es 200 y el Content-Type estext/html。
Devolver diccionario o lista (JSON)
Se llama automáticamente ajsonify()para convertir a una respuesta JSON; el Content-Type esapplication/json。
Ejemplo
def get_posts():
# Devolver un dict; Flask lo convierte automáticamente a JSON
return {
"status": "ok",
"data": [
{"id": 1, "title": "Tutorial de introducción a Flask"},
{"id": 2, "title": "Diseño de API RESTful"},
]
}
@app.get("/api/tags")
def get_tags():
# Devolver una lista; Flask la convierte automáticamente a JSON
return ["Python", "Flask", "Desarrollo web", "EJEMPLO"]
Devolver tuplas — controlar el código de estado y las cabeceras de respuesta
El formato de tupla es muy práctico y tiene tres formas:
Ejemplo
@app.get("/not-found")
def not_found():
return "<h1>Página no encontrada</h1>", 404
# Forma 2: (body, headers_dict)
@app.get("/custom-header")
def custom_header():
return "OK", {"X-Custom-Header": "ejemplo"}
# Forma 3: (body, status_code, headers_dict)
@app.post("/api/login")
def api_login():
# Devolver token y código de estado personalizado
return {"token": "abc123", "user": "ejemplo"}, 201, {"X-RateLimit": "100"}
Redirección
Usaredirect()la función para redirigir al usuario a otra URL:
Ejemplo
app = Flask(__name__)
@app.route("/")
def index():
# Redirigir a la página de inicio de sesión al acceder a la página principal
return redirect(url_for("login"))
@app.route("/login")
def login():
return "<h1>Por favor, inicie sesión primero</h1>"
@app.route("/old-page")
def old_page():
# La página antigua se migra permanentemente a la nueva, usando el código de estado 301
return redirect(url_for("new_page"), code=301)
@app.route("/new-page")
def new_page():
return "<h1>Esta es la nueva página</h1>"
El código de estado de redirección por defecto es303 See Other,aplicable a la redirección tras el envío de formularios (patrón PRG).
Para escenarios de migración permanente, se debe usarcode=301。
Terminar la solicitud — abort
Usarabort()Terminar inmediatamente la solicitud actual y devolver un error HTTP:
Ejemplo
@app.route("/post/<int:post_id>")
def view_post(post_id):
# Supongamos que el ID del artículo es solo 1-100
if post_id < 1 or post_id > 100:
# Devuelve 404 inmediatamente, el código posterior no se ejecutará
abort(404)
return f<h1>Artículo #{post_id}</h1>
@app.route("/admin")
def admin():
# Devuelve 403 cuando el acceso no está autorizado
abort(403, description=No tienes permiso para acceder a esta página)
make_response — controlar la respuesta manualmente
Cuando necesite configurar manualmente cookies o encabezados de respuesta personalizados, utilicemake_response():
Ejemplo
@app.route("/set-cookie")
def set_cookie():
# make_response envuelve el valor de retorno de la función de vista en un objeto Response
resp = make_response(<h1>Cookie establecida</h1>)
# Establecer Cookie en el objeto Response
resp.set_cookie("theme", "dark", max_age=60*60*24) # Válido por 24 horas
resp.set_cookie("lang", "zh-CN")
# También se pueden personalizar los encabezados de respuesta
resp.headers["X-Powered-By"] = "EJEMPLO-Flask"
return resp
Tabla de referencia rápida de atributos comunes de request
| Atributo | Tipo | Descripción | Valor de ejemplo |
|---|---|---|---|
| request.method | str | Método de solicitud HTTP | "GET", "POST" |
| request.path | str | Ruta de URL (sin dominio) | "/search" |
| request.args | MultiDict | Parámetros de consulta de URL | ?keyword=flask&page=1 |
| request.form | MultiDict | Datos de formulario POST | username=admin |
| request.json | dict o None | Cuerpo de solicitud JSON (parseado) | {"name": "ejemplo"} |
| request.files | FileMultiDict | Archivos subidos | request.files["avatar"] |
| request.headers | Headers | Encabezados de solicitud | request.headers["User-Agent"] |
| request.cookies | dict | Cookie enviada por el cliente | request.cookies.get("theme") |
| request.remote_addr | str | Dirección IP del cliente | "127.0.0.1" |