Разработка Edge Functions для сайта (Deno Deploy)

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.
Разработка и обслуживание любых видов сайтов:
Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Разработка Edge Functions для сайта (Deno Deploy)
Средняя
~2-3 рабочих дня
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    874
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    851

Разработка Edge Functions для сайта (Deno Deploy)

Deno Deploy — это распределённая runtime-платформа, запускающая JavaScript и TypeScript на V8 Isolates в 35+ регионах без холодного старта. В отличие от Lambda или Cloud Functions, код выполняется в миллисекундах от пользователя, потому что не поднимает контейнер — изолят уже готов.

Типичные задачи для Edge Functions на сайте: A/B-тестирование на уровне CDN, персонализация по геолокации, middleware для авторизации, проксирование запросов с трансформацией, генерация динамических OG-изображений.

Как работает Deno Deploy

Каждая функция — это ES module с обработчиком Deno.serve. Платформа не поддерживает файловую систему (кроме bundle), нет setTimeout с длинными задержками, нет фонового выполнения после ответа (кроме waitUntil в некоторых случаях).

// entry.ts
Deno.serve(async (req: Request) => {
  const url = new URL(req.url);

  if (url.pathname === '/api/geo') {
    const country = req.headers.get('x-deno-country') ?? 'unknown';
    const region = req.headers.get('x-deno-region') ?? 'unknown';

    return Response.json({ country, region });
  }

  return new Response('Not Found', { status: 404 });
});

Деплой через CLI:

deno install -A jsr:@deno/deployctl
deployctl deploy --project=my-site entry.ts

Middleware для авторизации

Часто нужно проверить JWT или сессионный токен до того, как запрос дойдёт до origin. На Edge это делается без roundtrip к бэкенду:

import { create, verify, getNumericDate } from 'https://deno.land/x/[email protected]/mod.ts';

const JWT_SECRET = Deno.env.get('JWT_SECRET')!;

async function getKey(secret: string): Promise<CryptoKey> {
  const enc = new TextEncoder();
  return await crypto.subtle.importKey(
    'raw',
    enc.encode(secret),
    { name: 'HMAC', hash: 'SHA-256' },
    false,
    ['sign', 'verify']
  );
}

Deno.serve(async (req: Request) => {
  const url = new URL(req.url);

  // Публичные маршруты пропускаем
  if (url.pathname.startsWith('/public') || url.pathname === '/') {
    return await fetch(req); // проксируем на origin
  }

  const authHeader = req.headers.get('Authorization');
  if (!authHeader?.startsWith('Bearer ')) {
    return new Response('Unauthorized', { status: 401 });
  }

  const token = authHeader.slice(7);

  try {
    const key = await getKey(JWT_SECRET);
    const payload = await verify(token, key);

    // Добавляем данные пользователя в заголовок для origin
    const modifiedReq = new Request(req, {
      headers: {
        ...Object.fromEntries(req.headers),
        'x-user-id': String(payload.sub),
        'x-user-role': String(payload.role ?? 'user'),
      },
    });

    return await fetch(modifiedReq);
  } catch {
    return new Response('Invalid token', { status: 401 });
  }
});

Геолокационная персонализация

Deno Deploy передаёт геоданные через заголовки. Полезно для редиректов по языку, показа региональных цен, блокировки по стране:

const COUNTRY_REDIRECTS: Record<string, string> = {
  RU: 'https://ru.example.com',
  BY: 'https://ru.example.com',
  DE: 'https://de.example.com',
  FR: 'https://fr.example.com',
};

Deno.serve((req: Request) => {
  const url = new URL(req.url);

  // Только для корня — не зацикливаемся
  if (url.pathname !== '/') {
    return fetch(req);
  }

  // Проверяем, не был ли уже редирект (cookie)
  const cookies = req.headers.get('Cookie') ?? '';
  if (cookies.includes('locale-selected=1')) {
    return fetch(req);
  }

  const country = req.headers.get('x-deno-country');
  const target = country ? COUNTRY_REDIRECTS[country] : null;

  if (target) {
    return new Response(null, {
      status: 302,
      headers: {
        Location: target,
        'Set-Cookie': 'locale-selected=1; Path=/; Max-Age=86400; SameSite=Lax',
      },
    });
  }

  return fetch(req);
});

Генерация OG-изображений на Edge

Satori — библиотека для рендеринга JSX в SVG — работает в Deno Deploy. Позволяет генерировать уникальные preview-картинки для каждой страницы без prebuild:

import satori from 'npm:[email protected]';
import { Resvg } from 'npm:@resvg/[email protected]';

Deno.serve(async (req: Request) => {
  const url = new URL(req.url);
  if (!url.pathname.startsWith('/og')) return new Response('Not Found', { status: 404 });

  const title = url.searchParams.get('title') ?? 'My Site';
  const description = url.searchParams.get('desc') ?? '';

  // Загружаем шрифт (кешируем в KV для скорости)
  const fontResponse = await fetch('https://your-cdn.com/fonts/Inter-Bold.ttf');
  const fontBuffer = await fontResponse.arrayBuffer();

  const svg = await satori(
    {
      type: 'div',
      props: {
        style: {
          display: 'flex',
          flexDirection: 'column',
          width: '100%',
          height: '100%',
          background: '#0f172a',
          padding: '60px',
          fontFamily: 'Inter',
        },
        children: [
          {
            type: 'h1',
            props: {
              style: { color: '#f8fafc', fontSize: 56, margin: 0, lineHeight: 1.2 },
              children: title,
            },
          },
          {
            type: 'p',
            props: {
              style: { color: '#94a3b8', fontSize: 28, marginTop: 24 },
              children: description,
            },
          },
        ],
      },
    },
    {
      width: 1200,
      height: 630,
      fonts: [{ name: 'Inter', data: fontBuffer, weight: 700, style: 'normal' }],
    }
  );

  const resvg = new Resvg(svg);
  const png = resvg.render().asPng();

  return new Response(png, {
    headers: {
      'Content-Type': 'image/png',
      'Cache-Control': 'public, max-age=86400, stale-while-revalidate=604800',
    },
  });
});

Кеширование с Deno KV

Deno KV — встроенное key-value хранилище с глобальной репликацией. Используется для кеша, счётчиков, rate limiting:

const kv = await Deno.openKv();

Deno.serve(async (req: Request) => {
  const url = new URL(req.url);
  const cacheKey = ['cache', url.pathname + url.search];

  // Проверяем кеш
  const cached = await kv.get<string>(cacheKey);
  if (cached.value) {
    return new Response(cached.value, {
      headers: {
        'Content-Type': 'application/json',
        'X-Cache': 'HIT',
      },
    });
  }

  // Запрос к origin
  const response = await fetch(`https://api.example.com${url.pathname}`);
  const data = await response.text();

  // Сохраняем с TTL 5 минут
  await kv.set(cacheKey, data, { expireIn: 5 * 60 * 1000 });

  return new Response(data, {
    headers: {
      'Content-Type': 'application/json',
      'X-Cache': 'MISS',
    },
  });
});

Rate limiting на Edge

const kv = await Deno.openKv();

async function rateLimit(ip: string, limit = 60, windowSeconds = 60): Promise<boolean> {
  const key = ['ratelimit', ip, Math.floor(Date.now() / (windowSeconds * 1000))];
  const entry = await kv.get<number>(key);
  const count = (entry.value ?? 0) + 1;

  if (count > limit) return false;

  await kv.set(key, count, { expireIn: windowSeconds * 1000 });
  return true;
}

Deno.serve(async (req: Request) => {
  const ip = req.headers.get('x-forwarded-for') ?? '0.0.0.0';
  const allowed = await rateLimit(ip);

  if (!allowed) {
    return new Response('Too Many Requests', {
      status: 429,
      headers: { 'Retry-After': '60' },
    });
  }

  return fetch(req);
});

Интеграция с существующим сайтом

Deno Deploy не заменяет весь бэкенд — он работает как Edge Layer перед origin. Схема: DNS → Deno Deploy Edge → Origin Server.

Конфигурация в deno.json:

{
  "tasks": {
    "dev": "deno run --allow-net --allow-env --watch entry.ts",
    "deploy": "deployctl deploy --project=my-site --prod entry.ts"
  },
  "imports": {
    "djwt": "https://deno.land/x/[email protected]/mod.ts"
  },
  "deploy": {
    "project": "my-site",
    "entrypoint": "entry.ts",
    "include": ["entry.ts", "lib/"]
  }
}

Сроки

Простая Edge Function (редирект, геолокация, базовый middleware) — 1–2 дня включая тестирование и деплой. Middleware с JWT-верификацией и проксированием — 2–3 дня. Генерация OG-изображений с кешированием через Deno KV — 3–5 дней. Полноценный Edge Layer с rate limiting, A/B-тестированием и аналитикой — 1–2 недели.