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

Сталкивался ли с SSR

2.2 Middle🔥 151 комментариев
#Python Core

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

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

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

Server-Side Rendering (SSR) в опыте Python Developer

Да, имею прямой опыт с SSR

Да, я работал с SSR (Server-Side Rendering) в контексте Python backend, хотя SSR часто ассоциируют с фронтом. На backend SSR реализуется через рендеринг HTML на сервере и отправку клиенту.

Варианты SSR, с которыми я работал

1. Jinja2 + Flask/FastAPI (классический подход)

Включал рендеринг HTML-шаблонов на сервере:

from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates

app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
templates = Jinja2Templates(directory="templates")

@app.get("/products/{product_id}")
async def get_product(request: Request, product_id: str):
    product = await fetch_product_from_db(product_id)
    return templates.TemplateResponse("product.html", {
        "request": request,
        "product": product,
        "reviews": await fetch_reviews(product_id)
    })

2. Асинхронный SSR с предзагрузкой данных

Оптимизировал SSR через параллельную загрузку зависимых данных:

import asyncio
from typing import Dict, Any

async def fetch_product_data(product_id: str) -> Dict[str, Any]:
    product_task = fetch_product_from_db(product_id)
    reviews_task = fetch_reviews(product_id)
    similar_task = fetch_similar_products(product_id)
    author_task = fetch_author_info(product_id)
    
    product, reviews, similar, author = await asyncio.gather(
        product_task,
        reviews_task,
        similar_task,
        author_task
    )
    
    return {
        "product": product,
        "reviews": reviews,
        "similar_products": similar,
        "author": author
    }

3. Кеширование рендеринга

Для статического контента кешировал отрендеренный HTML:

@app.get("/blog/{post_slug}")
async def get_blog_post(request: Request, post_slug: str):
    cache_key = f"post:{post_slug}:v1"
    cached_html = await redis.get(cache_key)
    if cached_html:
        return HTMLResponse(content=cached_html)
    
    post = await fetch_post(post_slug)
    html = templates.render("post.html", {"post": post})
    await redis.setex(cache_key, 86400, html)
    return HTMLResponse(content=html)

Проблемы SSR, которые я решал

1. Time to First Byte (TTFB)

Проблема: сервер долго рендерит. Решение: streaming response

from fastapi.responses import StreamingResponse

async def stream_product_response(product_id: str):
    yield b"<html><body><h1>Product</h1>"
    product = await fetch_product(product_id)
    yield f"<div>{product.name}</div>".encode()
    reviews = await fetch_reviews(product_id)
    for review in reviews:
        yield f"<p>{review.text}</p>".encode()
    yield b"</body></html>"

@app.get("/products/{product_id}")
async def get_product_stream(product_id: str):
    return StreamingResponse(
        stream_product_response(product_id),
        media_type="text/html"
    )

2. Race conditions при параллельной обработке

Решение: lock pattern

import asyncio
from asyncio import Lock

cache_locks = {}

async def fetch_with_single_lock(key: str, fetch_func):
    if key not in cache_locks:
        cache_locks[key] = Lock()
    
    async with cache_locks[key]:
        cached = await redis.get(key)
        if cached:
            return cached
        result = await fetch_func()
        await redis.set(key, result)
        return result

3. SEO и метаданные

Для корректного SEO нужны разные title/description:

@app.get("/blog/{post_slug}")
async def get_blog_post(request: Request, post_slug: str):
    post = await fetch_post(post_slug)
    return templates.TemplateResponse("post.html", {
        "request": request,
        "post": post,
        "meta_title": post.title,
        "meta_description": post.excerpt,
        "meta_image": post.cover_image
    })

SSR vs CSR (Client-Side Rendering)

ХарактеристикаSSRCSR
TTFBМедленнееБыстрее
Time to InteractiveБыстрееМедленнее
SEOИдеаленТребует инвестиций
Нагрузка на серверВысокаяНизкая

Современный подход: Hybrid

В последних проектах переходил на гибридный подход:

# backend: FastAPI отправляет JSON API
@app.get("/api/v1/products/{product_id}")
async def get_product_api(product_id: str):
    return await fetch_product(product_id)

# frontend: Next.js рендерит сам

Когда использовать SSR

✅ Используй если:

  • Критичен SEO
  • Нужна быстрая initial load
  • Контент статичен

❌ Избегай если:

  • Высокая интерактивность
  • Пиковая нагрузка на сервер

Итог

ССР на Python backend — мощный инструмент для SEO и performance. Требует понимания bottleneck'ов: кеширование, асинхронность, streaming.

Сталкивался ли с SSR | PrepBro