The core of web applications is "receiving requests, returning responses." This chapter provides a comprehensive explanation of how to read request data and construct various types of responses in Flask.
All examples can be run and verified directly in the development server.
* * *
## Request Objectββrequest
Flask provides all request information through the global proxy object `request`.
Although it is a "global" object, Flask internally uses a thread isolation mechanism to ensure that each request gets its own data.
## Instance
# Import request, a thread-safe proxy object
from flask import Flask, request
app = Flask( __name__ )
@app.route("/debug")
def debug():
# Output various request information to help understand the request object
return f"""
Request Debug Information
- Method: {request.method}
- Path: {request.path}
- Full URL: {request.url}
- Host: {request.host}
- Client IP: {request.remote_addr}
- User-Agent: {request.headers.get('User-Agent')}
"""
Visit http://127.0.0.1:5000/debug?foo=bar to see the detailed request information.
!(#)
* * *
## Getting Query Parametersββrequest.args
Parameters after the ? in the URL are called query parameters (Query String).
Use `request.args` to read them; it acts like a dictionary:
## Instance
@app.route("/search")
def search():
# request.args.get() safely retrieves parameters, returns None when the key does not exist
keyword= request.args.get("keyword","")# Get the search keyword
page = request.args.get("page","1")# Get the page number, default is 1
return f"""
Search Results
Keyword: {keyword}
Page: {page}
"""
# Test: /search?keyword=flask&page=2
# Test: /search?keyword=TUTORIAL
> It is recommended to use the .get() method instead of direct subscript access like request.args, because the latter will throw a KeyError when the key does not exist, resulting in a 400 error page.
* * *
## Getting Form Dataββrequest.form
To handle form data submitted via POST requests, use `request.form`:
## Instance
@app.route("/register", methods=["GET","POST"])
def register():
if request.method=="POST":
# Use the value of the field with name="username" in the form
username = request.form.get("username","")
password = request.form.get("password","")
if not username or not password:
return"
Error
Username and password cannot be empty
",400
return f"
Registration Successful
Welcome {username} to TUTORIAL!
"
# Display registration form for GET request
return"""
Register
Username:
Password:
"""
> Note: In the HTML page handling the form, the must have method="post" set, otherwise the data will be sent via the URL query string (GET method), and sensitive information will be exposed in the URL.
* * *
## Getting JSON Dataββrequest.json
In modern web development, JSON is the most common data format.
When the client sends a request with Content-Type: application/json, use `request.json` to get the parsed data:
## Instance
@app.post("/api/user")
def create_user():
# request.json returns JSON data already parsed into a Python dict
data = request.json# For example, client sends {"name": "tutorial", "email": "test@"}
# Safely get fields
name = data.get("name","Unknown")
email= data.get("email","Not provided")
# Directly return dict, Flask automatically converts to JSON response
return{
"message": "User created successfully",
"name": name,
"email": email
}
You can test with curl or Postman:
$ curl -X POST http://127.0.0.1:5000/api/user -H "Content-Type: application/json" -d '{"name": "tutorial", "email": "test@"}'{ "message": "User created successfully", "name": "tutorial", "email": "test@"}
* * *
## File Upload
To handle uploaded files, use `request.files`, combined with `secure_filename()` provided by Werkzeug to ensure the filename is safe:
## Instance
import os
from werkzeug.utils import secure_filename # Filter dangerous filename characters
# Configure upload directory (should be read from config in actual projects)
UPLOAD_DIR ="uploads"
@app.route("/upload", methods=["GET","POST"])
def upload_file():
if request.method=="POST":
# Check if a file was uploaded
if"file"not in request.files:
return"No file selected",400
file= request.files
# User might have submitted an empty form (no file selected)
if file.filename=="":
return"Filename is empty",400
# secure_filename filters out dangerous characters like path traversal
# For example, "../../etc/passwd" will be processed to "etc_passwd"
filename = secure_filename(file.filename)
# Ensure upload directory exists
os.makedirs(UPLOAD_DIR, exist_ok=True)
# Save file
file.save(os.path.join(UPLOAD_DIR, filename))
return f"File {filename} uploaded successfully"
# Display upload form for GET request
return"""
Upload File
"""
> If the form has a file upload field, the tag must have enctype="multipart/form-data" set, otherwise the file data will not be sent by the browser.
* * *
## Complete Guide to Response Types
View functions can return multiple types of data, and Flask will automatically convert them into appropriate HTTP responses.
Understanding this conversion rule is the key to mastering Flask.
### Returning Strings
The returned string serves as the HTML response body, with a default status code of 200 and Content-Type of text/html.
### Returning Dictionaries or Lists (JSON)
Automatically calls jsonify() to convert to a JSON response, with Content-Type of application/json.
## Instance
@app.get("/api/posts")
def get_posts():
# Return dict, Flask automatically converts to JSON
return{
"status": "ok",
"data": [
{"id": 1,"title": "Flask Beginner Tutorial"},
{"id": 2,"title": "RESTful API Design"},
]
}
@app.get("/api/tags")
def get_tags():
# Return list, Flask automatically converts to JSON
return["Python","Flask","Web Development","TUTORIAL"]
### Returning TuplesββControlling Status Codes and Response Headers
The tuple format is very practical and comes in three forms:
## Instance
# Form 1: (body, status_code)
@app.get("/not-found")
def not_found():
return"
Page not found
",404
# Form 2: (body, headers_dict)
@app.get("/custom-header")
def custom_header():
return"OK",{"X-Custom-Header": "tutorial"}
# Form 3: (body, status_code, headers_dict)
@app.post("/api/login")
def api_login():
# Return token and custom status code
return{"token": "abc123","user": "tutorial"},201,{"X-RateLimit": "100"}
* * *
## Redirection
Use the `redirect()` function to direct the user to another URL:
## Instance
from flask import Flask, redirect, url_for
app = Flask( __name__ )
@app.route("/")
def index():
# Redirect to login page when visiting the homepage
return redirect(url_for("login"))
@app.route("/login")
def login():
return"
Please log in first
"
@app.route("/old-page")
def old_page():
# Old page permanently moved to new page, use 301 status code
return redirect(url_for("new_page"),code=301)
@app.route("/new-page")
def new_page():
return"
This is the new page
"
The default redirect status code is 303 See Other, suitable for redirection after form submission (PRG pattern).
For permanent migration scenarios, use code=301.
* * *
## Aborting Requestsββabort
Use `abort()` to immediately terminate the current request and return an HTTP error:
## Instance
from flask import abort
@app.route("/post/")
def view_post(post_id):
# Assume article IDs are only 1-100
if post_id 100:
# Immediately return 404, subsequent code will not execute
abort(404)
return f"
Article #{post_id}
"
@app.route("/admin")
def admin():
# Return 403 for unauthorized access
abort(403, description="You do not have permission to access this page")
* * *
## make_responseββManual Response Control
When you need to manually set Cookies or customize response headers, use `make_response()`:
## Instance
from flask import make_response
@app.route("/set-cookie")
def set_cookie