From 3c4ebcd7d322c6910bcd56da0eacf2d3ac2f14d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=A1=D0=BE?= =?UTF-8?q?=D0=BB=D0=BE=D0=B2=D1=8C=D0=B5=D0=B2?= Date: Wed, 10 Jun 2026 14:04:29 +0300 Subject: [PATCH] =?UTF-8?q?refactor(cors):=20=D1=86=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=D1=80=D0=B0=D0=BB=D0=B8=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20?= =?UTF-8?q?CORS=20=D0=BD=D0=B0=20gateway,=20=D1=83=D0=B1=D1=80=D0=B0=D1=82?= =?UTF-8?q?=D1=8C=20per-service=20=D0=B8=D0=B7=20pcp-ui-service?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CORS-политика (allowedOriginPatterns:* + allowCredentials) переезжает в единый globalcors на pcp-gateway-service. После сворачивания фронта на gateway браузер ходит к бэкендам только через него (same-origin via Vite/nginx), поэтому per-service CORS в pcp-ui-service/WebConfig.kt стал мёртвым грузом. globalcors оставлен как страховка от cross-origin напрямую к gateway. --- config-repo/pcp-gateway-service.yaml | 13 ++++ .../slots_service/configuration/WebConfig.kt | 62 ------------------- 2 files changed, 13 insertions(+), 62 deletions(-) delete mode 100644 services/pcp-ui-service/src/main/kotlin/space/nstart/pcp/slots_service/configuration/WebConfig.kt diff --git a/config-repo/pcp-gateway-service.yaml b/config-repo/pcp-gateway-service.yaml index 57ec2d5..af1d5ac 100644 --- a/config-repo/pcp-gateway-service.yaml +++ b/config-repo/pcp-gateway-service.yaml @@ -10,6 +10,19 @@ spring: server: # WebFlux-вариант Spring Cloud Gateway (Boot 4 / Spring Cloud 2025.1). webflux: + # CORS теперь живёт ТОЛЬКО здесь — единая точка на edge. Раньше дублировался + # per-service (pcp-ui-service/WebConfig.kt), но после сворачивания фронта на + # gateway браузер ходит к бэкендам строго через него. Страховка от cross-origin + # к самому gateway (dev напрямую, LAN-адрес рабочей станции): allowedOriginPatterns + # "*" совместим с allowCredentials=true (в отличие от allowedOrigins "*"). + globalcors: + cors-configurations: + '[/**]': + allowedOriginPatterns: "*" + allowedMethods: "*" + allowedHeaders: "*" + allowCredentials: true + maxAge: 3600 routes: # --- Доменные сервисы. Префикс /api/pcp- СРЕЗАЕТСЯ (StripPrefix=2 убирает # 2 сегмента: api + pcp-), т.е. /api/pcp-tgu/api/plans -> бэкенд /api/plans. diff --git a/services/pcp-ui-service/src/main/kotlin/space/nstart/pcp/slots_service/configuration/WebConfig.kt b/services/pcp-ui-service/src/main/kotlin/space/nstart/pcp/slots_service/configuration/WebConfig.kt deleted file mode 100644 index 11631c8..0000000 --- a/services/pcp-ui-service/src/main/kotlin/space/nstart/pcp/slots_service/configuration/WebConfig.kt +++ /dev/null @@ -1,62 +0,0 @@ -package space.nstart.pcp.slots_service.configuration -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.web.cors.CorsConfiguration -import org.springframework.web.cors.UrlBasedCorsConfigurationSource -import org.springframework.web.filter.CorsFilter -import org.springframework.web.servlet.config.annotation.CorsRegistry -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer - - -@Configuration -class WebConfig : WebMvcConfigurer { - - override fun addCorsMappings(registry: CorsRegistry) { - // Внутренний ops-инструмент: UI открывают с разных хостов/IP (localhost, - // LAN-адрес рабочей станции, прод-сборка). Любой явный список origin'ов рано - // или поздно не совпадает с фактическим адресом UI → POST/PUT/DELETE отбивается - // как «Invalid CORS request» (same-origin GET проходит, т.к. идёт без Origin). - // Поэтому разрешаем любой origin. allowedOriginPatterns("*") совместим с - // allowCredentials=true (в отличие от allowedOrigins("*")). - registry.addMapping("/**") - .allowedOriginPatterns("*") - .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH") - .allowedHeaders("*") - .allowCredentials(true) - .maxAge(3600) - } - - // Альтернативный вариант через CorsFilter - @Bean - fun corsFilter(): CorsFilter { - val source = UrlBasedCorsConfigurationSource() - val config = CorsConfiguration().apply { - allowCredentials = true - // Любой origin — см. комментарий в addCorsMappings. - allowedOriginPatterns = listOf("*") - // Разрешенные заголовки - allowedHeaders = listOf( - "Origin", - "Content-Type", - "Accept", - "Authorization", - "X-Requested-With", - "Access-Control-Request-Method", - "Access-Control-Request-Headers" - ) - // Разрешенные методы - allowedMethods = listOf( - "GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH", "HEAD" - ) - // Заголовки, доступные клиенту - exposedHeaders = listOf( - "Access-Control-Allow-Origin", - "Access-Control-Allow-Credentials" - ) - maxAge = 3600L - } - - source.registerCorsConfiguration("/**", config) - return CorsFilter(source) - } -}