Перейти к содержимому

19. Server-Side Rendering

По умолчанию Astro генерирует статические HTML-файлы при сборке. Но иногда нужны живые данные: персонализированный контент, аутентификация, формы. Для этого Astro поддерживает SSR — рендеринг страниц на сервере по запросу.

Думай о разнице так: статика — это книга, напечатанная один раз; SSR — это диктор, который читает текст заново для каждого слушателя.


astro.config.mjs
import { defineConfig } from 'astro/config';
import node from '@astrojs/node';
export default defineConfig({
output: 'server', // 'static' | 'server' | 'hybrid'
adapter: node({
mode: 'standalone',
}),
});

Режимы:

  • 'static' — всё статично (по умолчанию)
  • 'server' — всё через SSR, кроме явно помеченных export const prerender = true
  • 'hybrid' — всё статично, кроме явно помеченных export const prerender = false

Окно терминала
# Vercel
npx astro add vercel
# Netlify
npx astro add netlify
# Node.js
npx astro add node
# Cloudflare Workers
npx astro add cloudflare

Каждый адаптер настраивает вывод проекта под конкретную платформу деплоя.


---
// Доступен только в SSR-режиме (output: 'server')
const { request, url, cookies, redirect } = Astro;
// Заголовки запроса
const userAgent = request.headers.get('user-agent');
const lang = request.headers.get('accept-language');
// URL параметры
const page = url.searchParams.get('page') ?? '1';
// IP клиента (через заголовок прокси)
const ip = request.headers.get('x-forwarded-for');
// Метод запроса
if (request.method === 'POST') {
const data = await request.json();
}
---

---
import { defineMiddleware } from 'astro:middleware';
// Чтение cookie
const theme = Astro.cookies.get('theme')?.value ?? 'dark';
const sessionToken = Astro.cookies.get('session')?.value;
// Запись cookie
Astro.cookies.set('theme', 'light', {
httpOnly: false,
secure: true,
sameSite: 'strict',
maxAge: 60 * 60 * 24 * 30, // 30 дней
path: '/',
});
// Удаление cookie
Astro.cookies.delete('session', { path: '/' });
---

src/pages/dashboard.astro
---
const session = Astro.cookies.get('session')?.value;
if (!session) {
return Astro.redirect('/login?from=/dashboard', 302);
}
const user = await validateSession(session);
if (!user) {
Astro.cookies.delete('session');
return Astro.redirect('/login', 302);
}
---
<h1>Привет, {user.name}!</h1>

---
// Отправляем HTML частями по мере готовности
import { renderToReadableStream } from 'react-dom/server';
---
<html>
<body>
<h1>Загружаем данные...</h1>
<!-- Astro автоматически стримит контент ниже -->
{async function* () {
const posts = await slowDatabase.getPosts();
for (const post of posts) {
yield <article><h2>{post.title}</h2></article>;
}
}()}
</body>
</html>