From b16eff2e76c365dd546780149612c9e07985b00a Mon Sep 17 00:00:00 2001 From: Vincent Guillet Date: Wed, 26 Nov 2025 15:14:53 +0100 Subject: [PATCH] Refactor environment and nginx configuration for improved API routing and proxy handling --- .../prestashop/PrestashopProxyController.java | 141 ------------------ client/nginx.conf | 23 ++- client/src/environments/environment.prod.ts | 2 +- client/src/environments/environment.ts | 2 +- 4 files changed, 24 insertions(+), 144 deletions(-) delete mode 100644 api/src/main/java/fr/gameovergne/api/controller/prestashop/PrestashopProxyController.java diff --git a/api/src/main/java/fr/gameovergne/api/controller/prestashop/PrestashopProxyController.java b/api/src/main/java/fr/gameovergne/api/controller/prestashop/PrestashopProxyController.java deleted file mode 100644 index 6973711..0000000 --- a/api/src/main/java/fr/gameovergne/api/controller/prestashop/PrestashopProxyController.java +++ /dev/null @@ -1,141 +0,0 @@ -package fr.gameovergne.api.controller.prestashop; - -import jakarta.servlet.http.HttpServletRequest; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.*; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.client.HttpStatusCodeException; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.util.UriComponentsBuilder; - -import java.io.BufferedReader; -import java.io.IOException; -import java.util.stream.Collectors; - -@RestController -@RequestMapping("/api/ps") -public class PrestashopProxyController { - - private static final Logger log = LoggerFactory.getLogger(PrestashopProxyController.class); - - private final RestTemplate restTemplate = new RestTemplate(); - - private final String baseUrl; // ex : https://shop.gameovergne.fr - private final String basicAuth; // base64 SANS le "Basic " - - public PrestashopProxyController( - @Value("${prestashop.base-url}") String baseUrl, - @Value("${prestashop.basic-auth}") String basicAuth - ) { - this.baseUrl = baseUrl; - this.basicAuth = basicAuth; - } - - // =============== Helpers =============== - - private String extractPath(HttpServletRequest request) { - // /api/ps/products/446 -> /products/446 - String fullPath = request.getRequestURI(); - String contextPath = request.getContextPath(); // souvent "" - String relative = fullPath.substring(contextPath.length()); - return relative.replaceFirst("^/api/ps", ""); - } - - private String readBody(HttpServletRequest request) throws IOException { - try (BufferedReader reader = request.getReader()) { - return reader.lines().collect(Collectors.joining(System.lineSeparator())); - } - } - - private ResponseEntity forward(HttpServletRequest request, - HttpMethod method, - String bodyIfAny) { - String path = extractPath(request); - String rawQuery = request.getQueryString(); - - UriComponentsBuilder builder = UriComponentsBuilder - .fromHttpUrl(baseUrl) - .path("/api") - .path(path); - - if (rawQuery != null && !rawQuery.isBlank()) { - builder.query(rawQuery); // on garde EXACTEMENT la query envoyée par Angular - } - - String url = builder.build(true).toUriString(); - log.info("[PrestaProxy] {} {}", method.name(), url); - - HttpHeaders headers = new HttpHeaders(); - - // Auth Presta (cachée côté backend) - headers.set(HttpHeaders.AUTHORIZATION, "Basic " + basicAuth); - - // On propage Accept/Content-Type du front pour garder le même comportement qu’en dev - String accept = request.getHeader(HttpHeaders.ACCEPT); - if (accept != null) { - headers.set(HttpHeaders.ACCEPT, accept); - } - - String contentType = request.getHeader(HttpHeaders.CONTENT_TYPE); - if (contentType != null) { - headers.set(HttpHeaders.CONTENT_TYPE, contentType); - } - - HttpEntity entity = new HttpEntity<>(bodyIfAny, headers); - - try { - ResponseEntity response = restTemplate.exchange( - url, - method, - entity, - String.class - ); - - // On renvoie EXACTEMENT le status + headers + body de Presta au front - return ResponseEntity - .status(response.getStatusCode()) - .headers(response.getHeaders()) - .body(response.getBody()); - - } catch (HttpStatusCodeException ex) { - // On propage aussi les erreurs Presta (4xx/5xx) sans les transformer en 500 Spring - HttpHeaders respHeaders = ex.getResponseHeaders() != null - ? ex.getResponseHeaders() - : new HttpHeaders(); - - log.error("[PrestaProxy] {} {} -> HTTP {}", - method.name(), url, ex.getStatusCode().value()); - - return ResponseEntity - .status(ex.getStatusCode()) - .headers(respHeaders) - .body(ex.getResponseBodyAsString()); - } - } - - // =============== Routes =============== - - @GetMapping("/**") - public ResponseEntity proxyGet(HttpServletRequest request) { - return forward(request, HttpMethod.GET, null); - } - - @DeleteMapping("/**") - public ResponseEntity proxyDelete(HttpServletRequest request) { - return forward(request, HttpMethod.DELETE, null); - } - - @PostMapping("/**") - public ResponseEntity proxyPost(HttpServletRequest request) throws IOException { - String body = readBody(request); // XML ou JSON, on ne touche à rien - return forward(request, HttpMethod.POST, body); - } - - @PutMapping("/**") - public ResponseEntity proxyPut(HttpServletRequest request) throws IOException { - String body = readBody(request); - return forward(request, HttpMethod.PUT, body); - } -} \ No newline at end of file diff --git a/client/nginx.conf b/client/nginx.conf index 22fcee0..f256e47 100644 --- a/client/nginx.conf +++ b/client/nginx.conf @@ -4,10 +4,31 @@ server { server_name _; + # Angular packagé par Nginx (classique) root /usr/share/nginx/html; index index.html; + # SPA Angular : toutes les routes front -> index.html location / { try_files $uri $uri/ /index.html; } -} \ No newline at end of file + + # === Proxy vers PrestaShop (équivalent proxy.conf.json "/ps") === + location /ps/ { + # /ps/... -> https://shop.gameovergne.fr/api/... + proxy_pass https://shop.gameovergne.fr/api/; + + # changeOrigin: true + proxy_set_header Host shop.gameovergne.fr; + + # Auth Basic comme dans ton proxy.conf.json Angular + proxy_set_header Authorization "Basic MkFRUEcxM01KOFgxMTdVNkZKNU5HSFBTOTNIRTM0QUI="; + + # HTTPS correct (SNI) + proxy_ssl_server_name on; + + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} diff --git a/client/src/environments/environment.prod.ts b/client/src/environments/environment.prod.ts index bc642a0..e79fa71 100644 --- a/client/src/environments/environment.prod.ts +++ b/client/src/environments/environment.prod.ts @@ -1,5 +1,5 @@ export const environment = { production: true, apiUrl: 'https://dev.vincent-guillet.fr/gameovergne-api/api', - psUrl: 'https://dev.vincent-guillet.fr/gameovergne-api/api/ps' + psUrl: '/ps' }; diff --git a/client/src/environments/environment.ts b/client/src/environments/environment.ts index 365cc04..8146fd1 100644 --- a/client/src/environments/environment.ts +++ b/client/src/environments/environment.ts @@ -1,5 +1,5 @@ export const environment = { production: false, apiUrl: 'http://localhost:3000/api', - psUrl: 'http://localhost:3000/api/ps' + psUrl: 'ps' };