Flask Request and Response

The core of a web application is "receiving requests and returning responses." This chapter comprehensively explains how to read request data and construct various types of responses in Flask.

All examples can be directly run and verified in the development server.


Request Object — request

Flask provides all request information through a global proxy object.requestAll request information is provided.

Although it is a "global" object, Flask internally uses thread isolation to ensure each request gets its own data.

Example

# 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"""
<h1>Request Debugging Info</h1>
    <ul>
<li>Method: {request.method}</li>
<li>Path: {request.path}</li>
<li>Full URL: {request.url}</li>
<li>Host: {request.host}</li>
<li>Client IP: {request.remote_addr}</li>
        <li>User-Agent:{request.headers.get('User-Agent')}</li>
    </ul>
    """

Visithttp://127.0.0.1:5000/debug?foo=barYou can see the detailed request information.


Get query parameters — request.args

In the URL?The parameters after it are called query parameters (Query String).

Usagerequest.argsReading it, it works like a dictionary:

Example

@app.route("/search")
def search():
    # request.args.get() safely gets the parameter, returns None when the key doesn't exist
    keyword = request.args.get("keyword", "")  # Get the query keyword
    page = request.args.get("page", "1")       # Get the page number, defaults to 1
    return f"""
<h1>Search Results</h1>
<p>Keyword: {keyword}</p>
<p>Page: {page}</p>
    """

# Test: /search?keyword=flask&page=2
# Test: /search?keyword=EXAMPLE

Recommended.get()Use the method instead of direct subscript access.request.args["key"], because the latter throws an exception when the key does not exist.KeyError, resulting in a 400 error page.


Get form data — request.form

To handle form data submitted by POST requests, userequest.form:

Example

@app.route("/register", methods=["GET", "POST"])
def register():
    if request.method == "POST":
        # Use the value of the name="username" field in the form
        username = request.form.get("username", "")
        password = request.form.get("password", "")

        if not username or not password:
            return "<h1>Error</h1><p>Username and password cannot be empty</p>", 400

        return f"<h1>Registration successful</h1><p>Welcome {username} to EXAMPLE!</p>"

    # Display registration form on GET request
    return """
<h1>Register</h1>
    <form method="post">
<p>Username: <input type="text" name="username"></p>
<p>Password: <input type="password" name="password"></p>
<p><input type="submit" value="Register"></p>
    </form>
    """

Note: In the HTML page that handles the form,<form>Must be setmethod="post", otherwise the data will be sent via the URL query string (GET method), and sensitive information will be exposed in the URL.


Get JSON data — request.json

In modern web development, JSON is the most common data format.

When the client sendsContent-Type: application/jsona request, userequest.jsonGet the parsed data:

Example

@app.post("/api/user")
def create_user():
    # request.json returns JSON data already parsed into a Python dict
    data = request.json  # For example, the client sends {"name": "example", "email": "test@example.com"}

    # Safely get the field
    name = data.get("name", "Unknown")
    email = data.get("email", "Not provided")

    # Return dict directly, Flask automatically converts it to a JSON response
    return {
        "message": "User created successfully",
        "name": name,
        "email": email
    }

Can be usedcurlor Postman to test:

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

File upload

Use this to handle uploaded files:request.files, combined with the Werkzeug-providedsecure_filename()Ensure the filename is safe:

Example

import os
from werkzeug.utils import secure_filename  # Filter dangerous filename characters

# Configure the upload directory (in a real project, this should be read from config)
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["file"]

        # User may 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" would be processed as "etc_passwd"
        filename = secure_filename(file.filename)

        # Ensure the upload directory exists
        os.makedirs(UPLOAD_DIR, exist_ok=True)

        # Save the file
        file.save(os.path.join(UPLOAD_DIR, filename))
        return fFile {filename} uploaded successfully

    # GET request shows upload form
    return """
<h1>Upload File</h1>
    <form method="post" enctype="multipart/form-data">
        <p><input type="file" name="file"></p>
<p><input type="submit" value="Upload"></p>
    </form>
    """

If the form has a file upload field,<form>The label must be setenctype="multipart/form-data", 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.

Return string

The returned string serves as the HTML response body, with a default status code of 200 and Content-Type oftext/html。

Return a dictionary or list (JSON)

Automatically calledjsonify()convert to JSON response, with Content-Type set toapplication/json。

Example

@app.get("/api/posts")
def get_posts():
    # Return dict, Flask automatically converts to JSON
    return {
        "status": "ok",
        "data": [
            {"id": 1, "title": Flask 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, "EXAMPLE"]

Returning a tuple—controlling the status code and response headers

The tuple format is very practical and has three forms:

Example

# Form 1: (body, status_code)
@app.get("/not-found")
def not_found():
    return <h1>Page Not Found</h1>, 404

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

# Form 3: (body, status_code, headers_dict)
@app.post("/api/login")
def api_login():
    # Return token and custom status code
    return {"token": "abc123", "user": "example"}, 201, {"X-RateLimit": "100"}

Redirect

Usageredirect()The function redirects the user to another URL:

Example

from flask import Flask, redirect, url_for

app = Flask(__name__)

@app.route("/")
def index():
    # Redirect to login page when visiting home page
    return redirect(url_for("login"))

@app.route("/login")
def login():
    return <h1>Please Log In First</h1>

@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 <h1>This is a new page</h1>

The default redirect status code is303 See Other, suitable for redirecting after form submission (PRG pattern).

For permanent migration scenarios, usecode=301。


Terminate Request — abort

Usageabort()Immediately terminate the current request and return an HTTP error:

Example

from flask import abort

@app.route("/post/<int:post_id>")
def view_post(post_id):
    # Assume article IDs are only 1-100
    if post_id < 1 or post_id > 100:
        # Immediately return 404, subsequent code will not execute
        abort(404)

    return f"<h1>Article #{post_id}</h1>"

@app.route("/admin")
def admin():
    # Return 403 for unauthorized access
    abort(403, description=You do not have permission to access this page)

make_response — manually control the response

When you need to manually set cookies or customize response headers, usemake_response():

Example

from flask import make_response

@app.route("/set-cookie")
def set_cookie():
    # make_response wraps the view function's return value into a Response object
    resp = make_response(<h1>Cookie Set</h1>)

    # Set cookie on the Response object
    resp.set_cookie("theme", "dark", max_age=60*60*24)  # Valid for 24 hours
    resp.set_cookie("lang", "zh-CN")

    # You can also customize response headers
    resp.headers["X-Powered-By"] = "EXAMPLE-Flask"

    return resp

Quick reference table of common request attributes

Property Type Description Example value
request.method str HTTP Request Method "GET", "POST"
request.path str URL Path (without domain name) "/search"
request.args MultiDict URL Query Parameters ?keyword=flask&page=1
request.form MultiDict POST Form Data username=admin
request.json dict or None JSON Request Body (parsed) {"name": "example"}
request.files FileMultiDict Uploaded file request.files["avatar"]
request.headers Headers Request headers request.headers["User-Agent"]
request.cookies dict Cookie Sent by the Client request.cookies.get("theme")
request.remote_addr str Client IP Address "127.0.0.1"
other extensions