Orbit
Функции Edge
Edge functions are small JavaScript handlers that run on Kapsule's edge network before a request reaches your project, so you can do redirects, header injection, A/B routing and bot filtering…
Граничные функции
Граничные функции представляют собой небольшие обработчики JavaScript, которые работают на граничной сети Kapsule перед тем, как запрос достигает вашего проекта. Они позволяют выполнять перенаправления, внедрение заголовков, маршрутизацию A/B и фильтрацию ботов без отправки запроса на ваше приложение. Данное руководство охватывает написание функции, принимаемые формы точки входа, сопоставление путей, взаимодействие нескольких функций, развёртывание и поведение при возбуждении исключения функцией.
Где они расположены
Откройте ваш проект в Orbit и щёлкните на вкладку Edge functions (Граничные функции). Каждая функция принадлежит проекту и отображается с её статусным значком: LIVE, PAUSED, NOT DEPLOYED или DEPLOY FAILED.

Создание функции
- Нажмите New function (Новая функция).
- Заполните поле Name (Имя, до 120 символов).
- Заполните поле Path pattern (Шаблон пути), URL-шаблон, на котором должна выполняться функция.
- Выберите Trigger (Триггер): Request (до источника), Response (после источника) или Both (оба).
- Выберите Environment scope (Область действия среды): All environments (все среды), Production only (только продакшен) или Preview only (только превью).
- Напишите обработчик в поле Function body (Тело функции).
- Нажмите Save (Сохранить), затем Deploy to edge (Развернуть на граничную сеть).
Объект request всегда находится в области видимости, а исходный код ограничен 64 КБ.
Написание обработчика
Вернёмся к Response, чтобы ответить на запрос на границе. Не возвращайте ничего или верните undefined, чтобы передать запрос на ваш проект без изменений.
export default {
async fetch(request) {
const url = new URL(request.url)
// Redirect /old to /new
if (url.pathname === '/old') {
return new Response(null, {
status: 301,
headers: { Location: '/new' },
})
}
// Returning nothing passes through to the origin
},
}
Форма именованной функции работает тоже:
export default async function handler(request) {
// Add a security header to every response
const response = await fetch(request)
const headers = new Headers(response.headers)
headers.set('X-Frame-Options', 'DENY')
return new Response(response.body, { status: response.status, headers })
}
Поддерживаемые формы точки входа
| Форма | Пример |
|---|---|
Объект с методом fetch | export default { async fetch(request) { ... } } |
Объект со стрелочным свойством fetch | export default { fetch: async (request) => { ... } } |
| Объявление именованной функции | export default async function handler(request) { ... } |
| Голое тело без экспорта | Напишите операторы напрямую без обёртки |
Всё остальное, что использует export default, например export default class, отклоняется при нажатии кнопки Save с ошибкой, указывающей на две подходящие формы. Проверка выполняется во время сохранения, а не во время развёртывания, поэтому вы узнаете об этом сразу и неработающая функция никогда не будет опубликована.
Шаблоны пути
Path pattern (Шаблон пути) определяет, какие запросы выполняют функцию. Он должен начинаться с / и может содержать до 2048 символов. * совпадает с любой последовательностью символов, а ? совпадает с одним символом. Шаблон без подстановочного знака совпадает с этим точным путём и всем, что находится под ним.
| Шаблон | Совпадает |
|---|---|
/* | Каждый путь |
/api/* | Что угодно, начинающееся с /api/ |
/blog/*/comments | Например /blog/my-post/comments |
/page | /page и всё, что находится под /page/ |
Объект request
request, это стандартный Fetch API Request. Вы можете читать URL, метод, заголовки и тело:
export default {
async fetch(request) {
const url = new URL(request.url)
const cookie = request.headers.get('cookie') ?? ''
const ua = request.headers.get('user-agent') ?? ''
if (ua.includes('BadBot')) {
return new Response('Forbidden', { status: 403 })
}
},
}
Не предполагайте, что заголовок существует только потому, что вы видели его на другой платформе. Прочитайте заголовки, которые фактически получает ваша функция (выведите их из функции или верните в ответе отладки на временный путь), прежде чем ветвиться по одному из них. Обработчик, который ветвится по заголовку, который никогда не присутствует, молча берёт неправильный путь при каждом запросе.
Обычные шаблоны
Перенаправление старых URL
export default {
async fetch(request) {
const url = new URL(request.url)
const redirects = {
'/old-about': '/about',
'/old-contact': '/contact',
}
const dest = redirects[url.pathname]
if (dest) return Response.redirect(url.origin + dest, 301)
},
}
Для нескольких простых перемещений из пути в путь используйте встроенный механизм перенаправления вместо этого: он не требует кода и настраивается в Settings. Смотрите раздел Configuring Redirects and Rewrites (Настройка перенаправлений и переписываний).
Добавление заголовков безопасности
export default async function handler(request) {
const response = await fetch(request)
const headers = new Headers(response.headers)
headers.set('X-Frame-Options', 'DENY')
headers.set('X-Content-Type-Options', 'nosniff')
headers.set('Referrer-Policy', 'strict-origin-when-cross-origin')
return new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers,
})
}
Для статических правил заголовков вам тоже не нужен код. Settings содержит раздел заголовков ответов с предустановками быстрого добавления для HSTS, CSP, no-embed, no-sniff, политики реферера и CORS.
Маршрутизация A/B
export default {
async fetch(request) {
const url = new URL(request.url)
const variant = Math.random() < 0.5 ? 'a' : 'b'
url.searchParams.set('variant', variant)
return fetch(url.toString(), request)
},
}
Область действия среды
| Область | Выполняется на |
|---|---|
| All environments (все среды) | Production, staging и каждый превью ветки |
| Production only (только продакшен) | Окружение production |
| Preview only (только превью) | Каждое непроизводственное окружение |
Разверните новую функцию как Preview only (только превью) первой, подтвердите её поведение на превью ветки, затем переключите на All environments (все среды). Граничная функция работает перед каждым запросом, поэтому ошибка в одной, это ошибка на каждой странице одновременно.
Взаимодействие нескольких функций
Все включённые функции вашего проекта оцениваются в порядке их создания. Для каждого запроса граничная сеть просматривает список и выполняет первую функцию, шаблон пути которой совпадает с путём запроса, а область видимости охватывает окружение.
- Если эта функция возвращает
Response, она отправляется и оценка прекращается. - Если она не возвращает ничего, оценка продолжается со следующей совпадающей функции.
- Если ни одна из них не возвращает
Response, запрос идёт на ваш проект в обычном режиме.
Это означает, что широкая функция с /*, созданная рано, может затенять более узкую, созданную позже, если широкая функция возвращает Response. Создавайте конкретные функции первыми или делайте так, чтобы широкая функция не возвращала ничего для путей, которые она не должна обрабатывать.
Развёртывание
Нажмите Deploy to edge (Развернуть на граничную сеть). Развёртывание перестраивает единый комбинированный маршрутизатор для всей граничной сети из текущего состояния базы данных, поэтому включение, отключение, редактирование или удаление любой функции переопубликовывает всё. Изменения обычно вступают в силу в течение нескольких секунд.
Каждая строка функции сохраняет Deploy log (журнал развёртывания), показывающий этапы последнего развёртывания, и значок DEPLOY FAILED (ошибка развёртывания) с ошибкой, если оно не прошло успешно.
Pause (пауза) исключает функцию из маршрутизатора без её удаления, что является самым быстрым способом отката неправильно работающей функции. Resume (возобновление) возвращает её обратно.
При возбуждении исключения функцией
Исключение внутри функции перехватывается на границе. Ошибка регистрируется и запрос переходит на ваш проект так, как если бы функция не вернула ничего.
Это сеть безопасности, а не система мониторинга. Функция, которая возбуждает исключение при каждом запросе, молча не срабатывает с точки зрения ваших посетителей, и ваш трафик просто ведёт себя так, как если бы функция не существует. Если функция перестаёт иметь желаемый эффект, заподозрите исключение, прежде чем заподозрить маршрутизацию.
Ограничения
- До 20 функций на проект. 21-я отклоняется.
- До 64 КБ исходного кода на функцию.
- До 120 символов для имени и 2048 символов для шаблона пути.
Дополнительное чтение
- Configuring Redirects and Rewrites (Настройка перенаправлений и переписываний), вариант без кода для правил пути
- Deploying Your Project (Развёртывание вашего проекта)
- Branch Preview Deployments in Orbit (Развёртывание превью ветки в Orbit) для тестирования функции перед отправкой в production