Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Процесс валидации информации в веб-приложении
Валидация — это проверка корректности данных перед их обработкой. Она происходит на нескольких уровнях, от фронтенда до базы данных.
Уровни валидации (layered approach)
1. Клиентская валидация (HTML5 + JavaScript)
Цель: быстрая обратная связь пользователю, экономия трафика.
<input
type="email"
name="email"
required
pattern="[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
placeholder="example@domain.com"
>
На JavaScript:
const form = document.querySelector("form");
form.addEventListener("submit", (e) => {
e.preventDefault();
const email = document.querySelector("input[name=email]").value;
// Простая проверка
if (!email.includes("@")) {
alert("Введите корректный email");
return;
}
// Если прошла клиентскую валидацию — отправляем на сервер
form.submit();
});
⚠️ ВАЖНО: клиентская валидация не безопасна! Хакер может её обойти через DevTools.
2. Серверная валидация (основная)
Цель: защита от подделок данных, безопасность.
FastAPI + Pydantic (рекомендуется)
from pydantic import BaseModel, EmailStr, Field, validator
from typing import Optional
class UserCreate(BaseModel):
email: EmailStr # Автоматически валидирует email
username: str = Field(..., min_length=3, max_length=50)
password: str = Field(..., min_length=8)
age: Optional[int] = Field(None, ge=0, le=150)
@validator("username")
def username_alphanumeric(cls, v):
if not v.replace("_", "").replace("-", "").isalnum():
raise ValueError("Username может содержать только буквы, цифры, - и _")
return v
@validator("password")
def password_strength(cls, v):
if not any(char.isupper() for char in v):
raise ValueError("Password должен содержать хотя бы одну заглавную букву")
return v
@app.post("/users")
async def create_user(user: UserCreate): # Pydantic автоматически валидирует
# Если здесь — данные уже прошли валидацию
db.add_user(user.email, user.username, user.password)
return {"status": "created"}
Django + DRF (Django REST Framework)
from rest_framework import serializers
class UserSerializer(serializers.ModelSerializer):
email = serializers.EmailField()
username = serializers.CharField(min_length=3, max_length=50)
password = serializers.CharField(min_length=8, write_only=True)
class Meta:
model = User
fields = ["email", "username", "password"]
def validate_username(self, value):
if User.objects.filter(username=value).exists():
raise serializers.ValidationError("Пользователь с таким username уже существует")
return value
def validate_password(self, value):
if not any(char.isupper() for char in value):
raise serializers.ValidationError("Password должен содержать заглавные буквы")
return value
def validate(self, data):
# Валидация на уровне объекта (несколько полей)
if data["email"] in BLOCKED_EMAILS:
raise serializers.ValidationError("Этот email заблокирован")
return data
class UserCreateView(generics.CreateAPIView):
serializer_class = UserSerializer
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True) # Валидация + выброс ошибок
self.perform_create(serializer)
return Response(serializer.data, status=status.HTTP_201_CREATED)
3. Валидация на уровне базы данных
Цель: последняя линия защиты, целостность данных.
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
username VARCHAR(50) NOT NULL UNIQUE,
age INT CHECK (age >= 0 AND age <= 150),
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
SQLAlchemy:
from sqlalchemy import Column, String, Integer, CheckConstraint, UniqueConstraint
from sqlalchemy.orm import declarative_base
Base = declarative_base()
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
email = Column(String(255), unique=True, nullable=False)
username = Column(String(50), unique=True, nullable=False)
age = Column(Integer, nullable=True)
__table_args__ = (
CheckConstraint("age >= 0 AND age <= 150"),
)
Полная схема валидации (на примере регистрации)
Пользователь заполнил форму
↓
[Клиент] Браузер проверяет HTML5 constraints
↓
[Клиент] JavaScript валидирует перед отправкой
↓
Отправляем POST /api/v1/users на сервер
↓
[Сервер] Парсим JSON
↓
[Сервер] Pydantic/Serializer валидирует тип данных
↓
[Сервер] Кастомные валидаторы проверяют бизнес-логику
↓
[Сервер] Проверяем уникальность в БД (email, username)
↓
[БД] Constraints проверяют целостность
↓
Данные успешно сохранены или получена ошибка 400 Bad Request
Типичные ошибки валидации
❌ Неправильный email
# Плохо
if "@" in email:
return True
# Хорошо
from pydantic import EmailStr
email: EmailStr # Использует RFC 5322 стандарт
❌ Отсутствие уникальности
# Плохо — нет проверки дубликатов
user = User(email="john@example.com")
db.add(user)
# Хорошо — проверяем уникальность
def validate_email(cls, v):
if User.objects.filter(email=v).exists():
raise ValueError("Email уже зарегистрирован")
return v
❌ Доверие клиентской валидации
# ОЧЕНЬ ПЛОХО — полагаться только на клиент
# Хакер пришлёт любые данные без клиентской валидации
# ПРАВИЛЬНО — валидация на сервере ВСЕГДА
❌ Слабая валидация пароля
# Плохо
if len(password) > 6:
return True
# Хорошо
password_requirements = [
(r"[A-Z]", "заглавные буквы"),
(r"[a-z]", "строчные буквы"),
(r"[0-9]", "цифры"),
(r"[!@#$%^&*]", "спецсимволы"),
]
for pattern, name in password_requirements:
if not re.search(pattern, password):
raise ValueError(f"Пароль должен содержать {name}")
Обработка ошибок валидации
from fastapi import FastAPI, HTTPException
from pydantic import ValidationError
app = FastAPI()
@app.exception_handler(ValidationError)
async def validation_exception_handler(request, exc):
return JSONResponse(
status_code=400,
content={
"error": "Validation failed",
"details": exc.errors() # Подробные ошибки
}
)
@app.post("/users")
async def create_user(user: UserCreate):
try:
user_data = user.dict()
# Дополнительная валидация бизнес-логики
if is_email_blocked(user.email):
raise HTTPException(status_code=400, detail="Email blocked")
db.create_user(user_data)
return {"status": "success"}
except Exception as e:
raise HTTPException(status_code=500, detail="Internal error")
Итог
Валидация — это многоуровневый процесс: клиент → сервер → БД. Каждый уровень выполняет свою роль. Никогда не доверяй только одному уровню!