← Назад к вопросам

В чем разница между тем что ввел пользователь и тем что обрабатывается функцией path, с точки зрения обработки запроса?

2.3 Middle🔥 121 комментариев
#FastAPI и Flask#REST API и HTTP

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между пользовательским вводом и обработкой path в функции

Это вопрос о различии между raw URL (то, что вводит пользователь или браузер) и parsed path (то, что получает функция-обработчик после нормализации и декодирования веб-фреймворком).

Raw URL пользователя

Когда пользователь вводит URL или кликает по ссылке, браузер отправляет запрос на сервер. Это может быть:

https://example.com/users/john%20doe?name=hello%20world

Особенности raw URL:

  • Специальные символы закодированы (URL encoding, percent-encoding)
  • Пробелы как %20
  • Кириллица как %D0%9F, %D0%A0 и т.д.
  • Может быть неправильно сформирован

Обработанный path в функции

Веб-фреймворк (FastAPI, Flask, Django) автоматически декодирует URL перед передачей в функцию:

# FastAPI
from fastapi import FastAPI

app = FastAPI()

@app.get("/users/{name}")
def get_user(name: str):
    # 'name' уже декодирован!
    print(name)  # "john doe" вместо "john%20doe"
    return {"user": name}

URL Encoding (процентное кодирование)

Зачем нужно кодирование:

URL может содержать специальные символы, которые имеют смысл в URL-синтаксисе. Их нужно кодировать, чтобы избежать конфликта:

Пользователь вводит: /search?q=python&pandas
В URL становится: /search?q=python%26pandas
                                  ^^^ & закодирован как %26

Таблица распространённых кодировок

СимволКодНазначение
Пробел%20Разделитель в пути
&%26Разделитель параметров
=%3DОператор присваивания в query
?%3FНачало query string
#%23Якорь (fragment)
%%25Сам символ кодирования
/%2FРазделитель пути
+%2BПлюс или пробел в query

Практические примеры

Пример 1: Простой путь с пробелом

from fastapi import FastAPI

app = FastAPI()

@app.get("/search/{query}")
def search(query: str):
    # Пользователь ввёл: /search/hello%20world
    # Функция получит: query = "hello world"
    print(f"Поиск: {query}")
    return {"results": [f"Result for {query}"]}

# Request: GET /search/hello%20world
# Вывод: Поиск: hello world

Пример 2: Кириллица в URL

@app.get("/users/{name}")
def get_user(name: str):
    # Пользователь кликнул: /users/Иван
    # В браузере стало: /users/%D0%98%D0%B2%D0%B0%D0%BD
    # FastAPI декодирует: name = "Иван"
    return {"user": name}

Пример 3: Специальные символы в query

from fastapi import FastAPI

app = FastAPI()

@app.get("/filter")
def filter_items(query: str):
    # Пользователь ввёл: /filter?query=price>100&tax=10%
    # В URL: /filter?query=price%3E100&tax=10%25
    # FastAPI получит: query = "price>100", tax = "10%"
    return {"filter": query}

Нормализация и обработка

Веб-фреймворк выполняет несколько действий с raw URL:

  1. URL декодирование (percent-decoding): %20 → пробел
  2. Нормализация пути: //users → /users
  3. Удаление query string: /path?query=value → /path
  4. Валидация (опционально): проверка на корректность
  5. Type conversion: путь параметры преобразуются в нужный тип
@app.get("/users/{user_id}/posts/{post_id}")
def get_post(user_id: int, post_id: int):
    # Пользователь: /users/123abc/posts/456def
    # FastAPI не будет искать совпадение (invalid)
    # Вернёт 404 или 422 (validation error)
    pass

Опасность: Injection атаки

Важно: даже если фреймворк декодирует URL, нужно проверять входные данные:

from fastapi import FastAPI
import sqlite3

app = FastAPI()

@app.get("/users/{user_id}")
def get_user(user_id: str):
    # ОПАСНО: SQL injection
    query = f"SELECT * FROM users WHERE id = {user_id}"
    # Если user_id = "1; DROP TABLE users; --"
    # Выполнится: SELECT * FROM users WHERE id = 1; DROP TABLE users; --
    
    # БЕЗОПАСНО: параметризованный запрос
    conn = sqlite3.connect(':memory:')
    cursor = conn.cursor()
    cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))
    return cursor.fetchone()

Ручное кодирование/декодирование

from urllib.parse import quote, unquote

# Кодирование (пользователь → URL)
original = "hello world & friends"
encoded = quote(original)
print(encoded)  # hello%20world%20%26%20friends

# Декодирование (URL → обработка)
decoded = unquote(encoded)
print(decoded)  # hello world & friends

# С безопасностью
query_string = "name=hello%20world&age=25"
from urllib.parse import parse_qs
parsed = parse_qs(query_string)
print(parsed)  # {'name': ['hello world'], 'age': ['25']}

Ключевые выводы

  • Raw URL: то, что вводит пользователь (закодировано)
  • path в функции: уже декодировано фреймворком
  • URL encoding: преобразует специальные символы в %HH формат
  • Фреймворк: автоматически декодирует path и query параметры
  • Безопасность: всегда валидируй и санитизируй входные данные, даже если они декодированы
  • Например FastAPI: использует pydantic для валидации типов и значений