🔧 Fix CORS and API endpoint issues

- Fix API endpoint paths (remove trailing slashes for 405 errors)
- Update API URLs to use api-todo.hyungi.net subdomain for HTTPS compatibility
- Improve CORS settings parsing in backend (handle brackets and quotes)
- Add frontend volume mount to docker-compose for real-time file updates
- Update Synology deployment config with wildcard CORS settings

Resolves:
- 405 Method Not Allowed errors
- Mixed Content security issues (HTTPS → HTTP)
- CORS preflight request failures
- Docker build requirements for every file change

Tested: API endpoints now correctly use HTTPS subdomain, eliminating security blocks
This commit is contained in:
hyungi
2025-09-24 18:54:07 +09:00
parent 2ccdf8c411
commit 03e6fe5b91
5 changed files with 92 additions and 13 deletions

View File

@@ -3,9 +3,15 @@
*/
// 환경에 따른 API URL 설정
const API_BASE_URL = window.location.hostname === 'localhost'
const API_BASE_URL = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'
? 'http://localhost:9000/api' // 로컬 개발 환경
: `${window.location.protocol}//${window.location.hostname}:9000/api`; // 시놀로지 배포 환경
: window.location.hostname === 'todo.hyungi.net'
? 'https://api-todo.hyungi.net/api' // API 서브도메인 (HTTPS 통일)
: window.location.hostname === '192.168.219.116'
? 'http://192.168.219.116:9000/api' // IP 직접 접근
: window.location.protocol === 'https:'
? `https://${window.location.hostname}:9000/api` // HTTPS 환경
: `http://${window.location.hostname}:9000/api`; // HTTP 환경
class ApiClient {
constructor() {
@@ -161,7 +167,7 @@ const AuthAPI = {
// Todo 관련 API
const TodoAPI = {
async getTodos(status = null, category = null) {
let url = '/todos/';
let url = '/todos/'; // 슬래시 추가
const params = new URLSearchParams();
if (status && status !== 'all') params.append('status', status);
@@ -175,27 +181,27 @@ const TodoAPI = {
},
async createTodo(todoData) {
return api.post('/todos/', todoData);
return api.post('/todos/', todoData); // 슬래시 추가
},
async updateTodo(id, todoData) {
return api.put(`/todos/${id}/`, todoData);
return api.put(`/todos/${id}`, todoData);
},
async deleteTodo(id) {
return api.delete(`/todos/${id}/`);
return api.delete(`/todos/${id}`);
},
async completeTodo(id) {
return api.put(`/todos/${id}/`, { status: 'completed' });
return api.put(`/todos/${id}`, { status: 'completed' });
},
async getTodayTodos() {
return api.get('/calendar/today/');
return api.get('/calendar/today');
},
async getTodoById(id) {
return api.get(`/todos/${id}/`);
return api.get(`/todos/${id}`);
},
async uploadImage(imageFile) {