10 KiB
Исправление Push-уведомлений
Проблема
Push-уведомления не работали по следующим причинам:
1. Кнопка "Включить уведомления" не зависела от состояния разрешения
До:
{!pushEnabled && 'Notification' in window && (
<button onClick={handleEnablePush}>Включить уведомления</button>
)}
Проблема: Кнопка показывалась, даже если пользователь заблокировал уведомления (Notification.permission === 'denied'). Клик по ней приводил к ошибке, так как браузер не давал повторно запросить разрешение.
После:
{!pushEnabled && 'Notification' in window && pushPermission !== 'denied' && (
<button onClick={handleEnablePush}>Включить уведомления</button>
)}
{pushPermission === 'denied' && (
<div className="alert alert-warning">
Push-уведомления заблокированы. Разрешите их в настройках браузера.
</div>
)}
Решение:
- Кнопка показывается только когда
pushPermission === 'default'(не запрашивалось) - Если
pushPermission === 'denied', показывается предупреждение с инструкцией
2. Service Worker мог не копироваться в dist при сборке
До:
// vite.config.ts
export default defineConfig({
plugins: [react()],
})
Проблема: Файл public/service-worker.js не копировался автоматически в dist/ при сборке, что приводило к 404 ошибке при регистрации.
После:
export default defineConfig({
plugins: [
react(),
{
name: 'copy-service-worker',
writeBundle() {
copyFileSync(
resolve(__dirname, 'public/service-worker.js'),
resolve(__dirname, 'dist/service-worker.js')
)
console.log('✅ Service worker скопирован в dist/')
}
}
],
})
Решение: Добавлен плагин Vite, который автоматически копирует service-worker.js в корень dist/ при каждой сборке.
3. Недостаточная диагностика ошибок
До:
console.error('Ошибка подключения Push-уведомлений:', error);
После:
console.log('📝 Регистрируем Service Worker...');
const registration = await navigator.serviceWorker.register('/service-worker.js');
console.log('✅ Service Worker зарегистрирован:', registration);
console.log('📝 Получаем VAPID ключ...');
const vapidPublicKey = await getVapidKey();
console.log('✅ VAPID ключ получен:', vapidPublicKey.substring(0, 20) + '...');
console.log('📝 Создаём Push подписку...');
const subscription = await registration.pushManager.subscribe({...});
console.log('✅ Push подписка создана:', subscription.endpoint);
Решение: Добавлены подробные логи на каждом этапе подключения Push-уведомлений для быстрой диагностики проблем.
Архитектура Push-уведомлений
Frontend (notificationService.ts)
1. Notification.requestPermission() → Запрос разрешения
2. navigator.serviceWorker.register() → Регистрация SW
3. GET /api/notifications/vapid-key → Получение публичного ключа
4. registration.pushManager.subscribe() → Создание подписки
5. POST /api/notifications/subscribe-push → Отправка подписки на сервер
Backend
1. GET /api/notifications/vapid-key → Возвращает VAPID_PUBLIC_KEY из .env
2. POST /api/notifications/subscribe-push → Сохраняет подписку в PushSubscription
3. Отправка уведомлений → webpush.sendNotification() для каждой подписки
Service Worker (public/service-worker.js)
self.addEventListener('push', (event) => {
const data = event.data.json();
self.registration.showNotification(data.title, {
body: data.body,
icon: data.icon || '/favicon.svg',
...
});
});
Проверка работы
1. Проверка VAPID ключей
curl https://ospab.host:5000/api/notifications/vapid-key \
-H "Authorization: Bearer YOUR_TOKEN"
Должен вернуть:
{
"success": true,
"publicKey": "BPtLNi3TY1ifUWTkgZrhxoEH6ihDgknFcgzc3xzFQg07PeuJ1TsJDQZqA32VqlxUo03g_mG0yKCKqADb4r5fnsM"
}
2. Проверка Service Worker
Откройте https://ospab.host → DevTools → Application → Service Workers
Должен быть зарегистрирован: /service-worker.js со статусом Activated
3. Проверка подписки
После нажатия "Включить уведомления" в консоли должны появиться:
📝 Запрашиваем разрешение на уведомления...
📝 Результат запроса разрешения: granted
📝 Регистрируем Service Worker...
✅ Service Worker зарегистрирован: ServiceWorkerRegistration {...}
📝 Ожидаем готовности Service Worker...
✅ Service Worker готов
📝 Получаем VAPID ключ...
✅ VAPID ключ получен: BPtLNi3TY1ifUWTk...
📝 Создаём Push подписку...
✅ Push подписка создана: https://fcm.googleapis.com/fcm/send/...
📝 Отправляем подписку на сервер...
✅ Push-уведомления успешно подключены
4. Проверка в базе данных
SELECT * FROM PushSubscription WHERE userId = YOUR_USER_ID;
Должна быть запись с endpoint, p256dh, auth.
5. Тестовая отправка
Можно создать тестовую отправку через backend:
import { sendPushNotification } from './modules/notification/push.service';
await sendPushNotification(userId, {
title: 'Тестовое уведомление',
body: 'Push-уведомления работают!',
icon: '/logo192.png'
});
Состояния Notification.permission
| Состояние | Описание | UI |
|---|---|---|
default |
Разрешение не запрашивалось | Показывается синяя кнопка "Включить уведомления" |
granted |
Разрешение получено | Кнопка скрыта, уведомления работают |
denied |
Пользователь заблокировал | Показывается красное предупреждение с инструкцией |
Разблокировка в браузерах
Chrome/Edge
- Нажмите на иконку 🔒 (замок) слева от адресной строки
- Найдите "Уведомления"
- Выберите "Разрешить"
- Обновите страницу
Firefox
- Откройте Настройки → Приватность и защита
- Прокрутите до раздела "Разрешения"
- Нажмите "Настройки" рядом с "Уведомления"
- Найдите
ospab.hostи измените на "Разрешить"
Safari
- Safari → Настройки → Веб-сайты
- Выберите "Уведомления"
- Найдите
ospab.hostи выберите "Разрешить"
Файлы изменены
-
✅
frontend/src/pages/dashboard/notifications.tsx- Добавлено состояние
pushPermission - Условный рендеринг кнопки/предупреждения
- Обновление состояния после запроса
- Добавлено состояние
-
✅
frontend/src/services/notificationService.ts- Добавлены подробные логи в
requestPushPermission() - Эмодзи-маркеры для быстрого поиска в консоли
- Добавлены подробные логи в
-
✅
frontend/vite.config.ts- Плагин копирования
service-worker.jsвdist/
- Плагин копирования
Деплой
# Frontend
cd frontend
npm run build
# Скопируйте dist/ на production сервер
# Backend (если были изменения)
cd backend
npm run build
pm2 restart ospab-backend
Возможные проблемы
Service Worker не регистрируется
- Проверка: DevTools → Application → Service Workers
- Причина: Файл
service-worker.jsне доступен по адресуhttps://ospab.host/service-worker.js - Решение: Убедитесь, что файл скопирован в корень
dist/и доступен через nginx
403 Forbidden при запросе VAPID ключа
- Проверка: Network →
/api/notifications/vapid-key→ Response - Причина: Не передаётся токен авторизации
- Решение: Проверьте, что в localStorage есть
access_token
Push-уведомления не приходят
- Проверка: Console → Ошибки от
webpush.sendNotification() - Причина: Неправильные VAPID ключи или подписка устарела
- Решение: Перегенерируйте VAPID ключи (
npx web-push generate-vapid-keys) и переподпишитесь
Подписка создаётся, но не сохраняется в БД
- Проверка: Console → Network →
/api/notifications/subscribe-push→ Response - Причина: Ошибка на backend при сохранении в Prisma
- Решение: Проверьте логи backend (
pm2 logs ospab-backend)
Статус: ✅ Исправлено и готово к тестированию Дата: 2025-01-20