В чем разница между тем что ввел пользователь и тем что обрабатывается функцией path, с точки зрения обработки запроса?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Разница между пользовательским вводом и обработкой 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:
- URL декодирование (percent-decoding): %20 → пробел
- Нормализация пути: //users → /users
- Удаление query string: /path?query=value → /path
- Валидация (опционально): проверка на корректность
- 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 для валидации типов и значений