2025-11-10 23:55:41 +00:00
|
|
|
|
# Решение CORS Error
|
|
|
|
|
|
|
|
|
|
|
|
## Что такое CORS?
|
|
|
|
|
|
|
|
|
|
|
|
CORS (Cross-Origin Resource Sharing) - это механизм безопасности браузера, который блокирует запросы между разными доменами/портами.
|
|
|
|
|
|
|
|
|
|
|
|
## Проблема
|
|
|
|
|
|
|
|
|
|
|
|
При разработке:
|
|
|
|
|
|
- **Frontend** (Flutter Web) работает на `http://localhost:xxxxx` (случайный порт)
|
|
|
|
|
|
- **Backend** работает на `http://localhost:8000`
|
|
|
|
|
|
- Браузер блокирует запросы между этими портами
|
|
|
|
|
|
|
|
|
|
|
|
## Решение
|
|
|
|
|
|
|
|
|
|
|
|
### 1. ✅ Backend настроен (исправлено 19 окт 2025)
|
|
|
|
|
|
|
|
|
|
|
|
В файле `mnemo_cards_backend/lib/api/mnemo_shelf.dart` добавлена правильная CORS конфигурация:
|
|
|
|
|
|
|
|
|
|
|
|
```dart
|
|
|
|
|
|
final corsConfig = {
|
|
|
|
|
|
'Access-Control-Allow-Origin': '*',
|
|
|
|
|
|
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS',
|
|
|
|
|
|
'Access-Control-Allow-Headers': 'Origin, Content-Type, Accept, Authorization, user_token, request_token, app_version',
|
|
|
|
|
|
'Access-Control-Expose-Headers': 'Authorization',
|
|
|
|
|
|
'Access-Control-Max-Age': '86400',
|
|
|
|
|
|
};
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**⚠️ ВАЖНО:** CORS middleware должен быть **ПЕРВЫМ** в pipeline, иначе preflight запросы (OPTIONS) будут блокироваться авторизацией:
|
|
|
|
|
|
|
|
|
|
|
|
```dart
|
|
|
|
|
|
final handler = Pipeline()
|
|
|
|
|
|
.addMiddleware(corsHeaders(headers: corsConfig)) // ← CORS ПЕРВЫМ!
|
|
|
|
|
|
.addMiddleware(logRequests(logger: logger('app')))
|
|
|
|
|
|
.addMiddleware(appAuthorize(getIt.get<UserManager>()))
|
|
|
|
|
|
.addHandler(rootRouter);
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Это позволяет:
|
|
|
|
|
|
- ✅ Принимать запросы с любого origin (`*`)
|
|
|
|
|
|
- ✅ Разрешает все необходимые HTTP методы
|
|
|
|
|
|
- ✅ Разрешает кастомные заголовки (`user_token`, `request_token`, `app_version`)
|
|
|
|
|
|
- ✅ Разрешает читать заголовок `Authorization` в ответе
|
|
|
|
|
|
- ✅ OPTIONS запросы обрабатываются до проверки авторизации
|
|
|
|
|
|
|
|
|
|
|
|
### 2. 🚀 Запуск Backend
|
|
|
|
|
|
|
|
|
|
|
|
Используйте скрипт для запуска backend в режиме разработки:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
cd /Users/dmitry/StudioProjects/mnemo_cards/mnemo_cards_backend
|
|
|
|
|
|
./run_dev.sh
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Backend будет доступен на `http://localhost:8000`
|
|
|
|
|
|
|
|
|
|
|
|
### 3. 🌐 Запуск Frontend
|
|
|
|
|
|
|
|
|
|
|
|
В отдельном терминале запустите веб-версию:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
cd /Users/dmitry/StudioProjects/mnemo_cards/mnemo_cards_web_v2
|
|
|
|
|
|
flutter run -d chrome
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 4. ✔️ Проверка
|
|
|
|
|
|
|
|
|
|
|
|
После запуска обоих сервисов:
|
|
|
|
|
|
1. Откройте DevTools в Chrome (F12)
|
|
|
|
|
|
2. Перейдите на вкладку Network
|
|
|
|
|
|
3. Проверьте что запросы к `/packs/previews`, `/games` и т.д. успешны
|
|
|
|
|
|
4. В заголовках ответа должны быть CORS заголовки
|
|
|
|
|
|
|
|
|
|
|
|
## Альтернативные решения (если не помогло)
|
|
|
|
|
|
|
|
|
|
|
|
### Вариант 1: Отключить web security в Chrome (только для разработки!)
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# macOS
|
|
|
|
|
|
open -n -a "Google Chrome" --args --user-data-dir="/tmp/chrome_dev_session" --disable-web-security
|
|
|
|
|
|
|
|
|
|
|
|
# Linux
|
|
|
|
|
|
google-chrome --disable-web-security --user-data-dir="/tmp/chrome_dev_session"
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
⚠️ **Внимание**: Это небезопасно! Используйте только для разработки.
|
|
|
|
|
|
|
|
|
|
|
|
### Вариант 2: Использовать Flutter с --web-port
|
|
|
|
|
|
|
|
|
|
|
|
Запускайте Flutter на фиксированном порту:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
flutter run -d chrome --web-port=8080
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Вариант 3: Production CORS (для деплоя)
|
|
|
|
|
|
|
2025-11-16 12:15:21 +00:00
|
|
|
|
Для production версии:
|
2025-11-10 23:55:41 +00:00
|
|
|
|
|
2025-11-16 12:15:21 +00:00
|
|
|
|
1. **Backend** уже настроен с правильными CORS настройками ✅
|
2025-11-19 20:21:15 +00:00
|
|
|
|
2. **Frontend** использует `https://api.mnemo-cards.online` (nginx:443) ✅
|
2025-11-16 12:15:21 +00:00
|
|
|
|
3. **Nginx** настроен без конфликтующих COEP/COOP headers ✅
|
|
|
|
|
|
|
|
|
|
|
|
Текущая конфигурация позволяет:
|
2025-11-19 22:41:54 +00:00
|
|
|
|
- ✅ Запросы с `mnemo-cards.online` на `https://api.mnemo-cards.online`
|
2025-11-16 12:15:21 +00:00
|
|
|
|
- ✅ Все необходимые HTTP методы и headers
|
|
|
|
|
|
- ✅ Preflight OPTIONS запросы
|
2025-11-10 23:55:41 +00:00
|
|
|
|
|
|
|
|
|
|
## Диагностика
|
|
|
|
|
|
|
|
|
|
|
|
Если CORS ошибка все еще возникает:
|
|
|
|
|
|
|
|
|
|
|
|
1. **Проверьте что backend запущен**:
|
|
|
|
|
|
```bash
|
|
|
|
|
|
curl http://localhost:8000/games
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
2. **Проверьте CORS заголовки**:
|
|
|
|
|
|
```bash
|
|
|
|
|
|
curl -H "Origin: http://localhost:8080" -H "Access-Control-Request-Method: POST" -H "Access-Control-Request-Headers: X-Requested-With" -X OPTIONS --verbose http://localhost:8000/games
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
3. **Посмотрите логи backend** - там будут видны все входящие запросы
|
|
|
|
|
|
|
|
|
|
|
|
4. **Проверьте что ApiConfig использует правильный URL**:
|
|
|
|
|
|
```dart
|
|
|
|
|
|
// В lib/domain/config/api_config.dart
|
|
|
|
|
|
static const String baseUrl = 'http://localhost:8000';
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Полезные ссылки
|
|
|
|
|
|
|
|
|
|
|
|
- [MDN: CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)
|
|
|
|
|
|
- [shelf_cors_headers package](https://pub.dev/packages/shelf_cors_headers)
|
|
|
|
|
|
- [Flutter Web: CORS](https://docs.flutter.dev/platform-integration/web/building#handling-cors-errors-only-applicable-to-web)
|
|
|
|
|
|
|