Короткие ссылки нужны не только для твитера. Если вы делаете лендинг с UTM-метками, шерите ссылки в рассылках или просто хотите контролировать, куда ведёт каждый переход — свой короткий сервис удобнее, чем сторонние сервисы с рекламой и лимитами. Firebase позволяет собрать полноценный URL-shortener за один вечер, без серверов и с бесплатным тарифом, которого хватает с головой для большинства задач.
- Что мы собираем и почему именно Firebase
- Что понадобится перед началом
- Шаг 1. Создаём проект и подключаем Hosting
- Шаг 2. Настраиваем Firestore для хранения ссылок
- Шаг 3. Пишем Cloud Function для создания коротких ссылок
- Шаг 4. Настраиваем редиректы в firebase.json
- Шаг 5. Делаем простой фронтенд
- Шаг 6. Деплоим и проверяем
- Правила безопасности Firestore: не забудьте это
- Сравнение подходов: когда Firebase подходит, а когда нет
- Что выбрать в зависимости от вашей ситуации
- Частые ошибки и как их избежать
- Практические рекомендации
- Что можно улучшить, если базовая версия заработала
- Итог
Что мы собираем и почему именно Firebase
Итоговый сервис будет работать так: вы отправляете длинный URL — получаете короткий код, который перенаправляет на оригинал. Вся логика умещается в три компонента:
- Firebase Hosting — раздаёт статику и обрабатывает редиректы.
- Cloud Firestore — хранит соответствие «короткий код → длинный URL».
- Cloud Functions — генерирует коды и записывает их в базу.
Почему Firebase, а не свой сервер или другой бэкенд:
- Бесплатный Spark-план даёт 50 000 чтений Firestore в день, 2 млн загрузок с Hosting и 2 млн вызовов Cloud Functions — для личного или небольшого проекта этого более чем достаточно.
- Не нужно настраивать сервер, сертификаты, домены — всё уже работает внутри экосистемы Google.
- Редиректы на уровне Hosting работают быстро, потому что отдаются с edge-серверов Google без участия вашего кода.
Что понадобится перед началом
- Аккаунт Google и проект в Firebase Console.
- Node.js версии 18+ и установленный Firebase CLI (
npm install -g firebase-tools). - Базовое понимание JavaScript — писать сложного ничего не нужно, но читать и копировать код придётся.
- Домен (опционально) — можно использовать бесплатный поддомен
your-project.web.app, но для серьёзного проекта лучше привязать свой.
Шаг 1. Создаём проект и подключаем Hosting
В Firebase Console создаём новый проект, включаем Hosting и инициализируем его локально:
firebase login
firebase init hosting На вопрос «What do you want to use as your public directory?» отвечаем public. На вопрос о конфигурации как single-page app — отказываемся, если не собираем SPA. После инициализации в корне проекта появится папка public и файл firebase.json.
Шаг 2. Настраиваем Firestore для хранения ссылок
В консоли включаем Cloud Firestore (режим production или test — для начала можно test, потом настроите правила безопасности). Создаём коллекцию links. Каждый документ будет содержать:
shortCode— короткий код (например,abc123).longUrl— оригинальный длинный URL.createdAt— дата создания.clicks— счётчик переходов (опционально).
Структура простая, и этого достаточно для работы. Если позже захотите добавить аналитику по странам или устройствам — просто расширите документ.
Шаг 3. Пишем Cloud Function для создания коротких ссылок
Инициализируем Functions:
firebase init functions В файле functions/index.js пишем функцию, которая принимает длинный URL, генерирует уникальный код и сохраняет его в Firestore:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
function generateCode(length = 6) {
const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
let result = '';
for (let i = 0; i < length; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
}
exports.createShortLink = functions.https.onCall(async (data, context) => {
const { longUrl } = data;
if (!longUrl || !longUrl.startsWith('http')) {
throw new functions.https.HttpsError('invalid-argument', 'Valid URL is required');
}
const shortCode = generateCode();
await db.collection('links').doc(shortCode).set({
longUrl,
createdAt: admin.firestore.FieldValue.serverTimestamp(),
clicks: 0
});
return { shortCode };
}); Обратите внимание: мы используем onCall, а не HTTP-триггер. Это удобнее для вызова с фронтенда — Firebase SDK сам обрабатывает авторизацию и сериализацию данных.
Шаг 4. Настраиваем редиректы в firebase.json
Самое интересное — как сделать так, чтобы your-domain.com/abc123 перенаправлял на длинный URL без серверной логики. Для этого в firebase.json добавляем rewrite-правило:
{
"hosting": {
"public": "public",
"rewrites": [
{
"source": "/:shortCode",
"function": "redirectFunction"
}
]
}
} Теперь пишем функцию redirectFunction, которая ищет код в Firestore и делает редирект:
exports.redirectFunction = functions.https.onRequest(async (req, res) => {
const shortCode = req.path.split('/')[1];
if (!shortCode) {
res.status(404).send('Not found');
return;
}
const doc = await db.collection('links').doc(shortCode).get();
if (!doc.exists) {
res.status(404).send('Link not found');
return;
}
const { longUrl, clicks } = doc.data();
await doc.ref.update({ clicks: clicks + 1 });
res.redirect(302, longUrl);
}); Важный момент: мы используем onRequest, а не onCall, потому что rewrite в Hosting работает именно с HTTP-запросами. Редирект отдаётся на edge-серверах Google, поэтому скорость будет отличной.
Шаг 5. Делаем простой фронтенд
В папке public создаём index.html — минимальную форму для создания ссылок:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>URL Shortener</title>
<script src="https://www.gstatic.com/firebasejs/9.0.0/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/9.0.0/firebase-functions-compat.js"></script>
</head>
<body>
<input type="text" id="longUrl" placeholder="Вставьте длинный URL">
<button onclick="createLink()">Сократить</button>
<p id="result"></p>
<script>
const firebaseConfig = { /* ваш конфиг */ };
firebase.initializeApp(firebaseConfig);
const functions = firebase.functions();
const createShortLink = functions.httpsCallable('createShortLink');
async function createLink() {
const url = document.getElementById('longUrl').value;
const { data } = await createShortLink({ longUrl: url });
document.getElementById('result').textContent =
`Короткая ссылка: window.location.origin/{data.shortCode}`;
}
</script>
</body>
</html> Это базовая версия. При желании можно добавить копирование в буфер, историю ссылок, QR-коды — но для начала хватит и этого.
Шаг 6. Деплоим и проверяем
firebase deploy После деплоя вы получите URL вида https://your-project.web.app. Открываете, вставляете длинную ссылку, нажимаете кнопку — получаете короткий код. Переходите по короткой ссылке — попадаете на оригинал. Всё работает.
Правила безопасности Firestore: не забудьте это
По умолчанию в production-режиме Firestore запрещает все операции. Если этого не сделать, любой сможет читать и писать в вашу базу. Минимальные правила для нашего случая:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /links/{shortCode} {
allow read: if true; // нужно для редиректов
allow write: if false; // запись только через Cloud Functions
}
}
} Запрет на запись для клиентов — ключевой момент. Все новые ссылки должны создаваться только через Cloud Function, где мы контролируем валидацию и генерацию кода.
Сравнение подходов: когда Firebase подходит, а когда нет
| Критерий | Firebase URL-shortener | Свой сервер (Node.js + PostgreSQL) | Готовый сервис (Bitly, Rebrandly) |
|---|---|---|---|
| Сложность запуска | Низкая — за вечер | Средняя — нужен сервер, деплой, мониторинг | Минимальная — регистрация и API |
| Стоимость при малых объёмах | Бесплатно | От $5/мес за VPS | Бесплатно с ограничениями |
| Контроль над данными | Полный | Полный | Частичный |
| Кастомизация редиректов | Ограничена функциями Firebase | Любая | Зависит от тарифа |
| Масштаб выше 100 000 переходов/день | Нужно следить за лимитами | Горизонтальное масштабирование | Тарифы с оплатой за объём |
| Аналитика кликов | Нужно дорабатывать | Любая | Встроенная |
Что выбрать в зависимости от вашей ситуации
Если вам нужен личный короткий сервис для проекта с небольшим трафиком — Firebase идеален. Бесплатно, быстро, без головной боли с инфраструктурой. Хватит на годы.
Если вы делаете продукт для клиентов с аналитикой, брендированными доменами и высокими нагрузками — начните с Firebase для MVP, но планируйте миграцию на собственный бэкенд, когда перестанут хватать лимиты или понадобится гибкость.
Если вам критична встроенная аналитика, командный доступ и SLA — используйте Bitly или Rebrandly. Не изобретайте велосипед, если это не ваш основной продукт.
Частые ошибки и как их избежать
- Коллизия коротких кодов. Случайная генерация не гарантирует уникальность. Решение: перед записью проверяйте, существует ли документ с таким кодом, и если да — генерируйте новый. Либо используйте последовательные ID с префиксом, но это менее эстетично.
- Отсутствие валидации URL. Если не проверять входные данные, можно получить пустые ссылки, javascript: протоколы или ссылки на фишинговые сайты. Всегда проверяйте формат на уровне Cloud Function.
- Забыли про правила Firestore. Открытая база — это мусорная свалка через неделю. Любой бот начнёт писать туда что угодно.
- Нет обработки ошибок на фронтенде. Если Cloud Function упадёт, пользователь должен увидеть понятное сообщение, а не молча ждать.
- Использование test-режима Firestore в продакшене. Он автоматически закрывается через 30 дней. Переключитесь на production и настройте правила до того, как сервис начнёт работать по-настоящему.
Практические рекомендации
- Длина кода. 6 символов из алфавита a-zA-Z0-9 дают около 56 миллиардов комбинаций. Для личного проекта этого хватит с запасом. Если генерируете миллионы ссылок — увеличьте до 8 символов.
- Кэширование редиректов. Добавьте заголовок
Cache-Control: public, max-age=300в ответ redirectFunction. Это снизит нагрузку на Firestore для популярных ссылок. - Логирование. Используйте
functions.logger.info()для записи каждого создания ссылки. Это поможет отследить аномалии, если что-то пойдёт не так. - Резервное копирование. Настройте экспорт Firestore через
firestore:exportпо расписанию. Потерять базу ссылок — значит сломать все короткие ссылки, которые вы когда-либо разослали. - Мониторинг квот. В Firebase Console есть вкладка Usage & billing. Добавьте уведомления о приближении к лимитам, чтобы не обнаружить внезапно неработающий сервис.
Что можно улучшить, если базовая версия заработала
Когда ядро работает, хочется добавить полезных вещей:
- QR-код для каждой короткой ссылки — генерируется на фронтенде за две строки с любой библиотекой.
- Пользовательские алиасы — возможность задать свой код вместо случайного, с проверкой на занятость.
- Истечение ссылок — добавьте поле
expiresAtи проверяйте его в функции редиректа. - Статистика переходов — записывайте каждый переход в отдельную коллекцию с временем, user-agent и IP (с учётом политик конфиденциальности).
- Защита от спама — ограничьте количество создаваемых ссылок с одного IP через rate limiting на уровне Cloud Functions.
Итог
Firebase даёт всё необходимое для запуска собственного URL-shortener без серверов, без абонентской платы и с минимальным объёмом кода. Базовая версия — Hosting, Firestore и две Cloud Functions — покрывает 90% задач. Главное — не забыть про правила безопасности, валидацию входных данных и обработку ошибок. Если проект вырастет из личного инструмента в продукт — архитектура позволит постепенно наращивать функциональность без переписывания с нуля.
Начните с простой формы и редиректа. Запустите за один вечер. Если доживёте до момента, когда Firebase начнёт ограничивать вас — значит, проект вырос, и это уже другая, гораздо более приятная проблема.
