Docker化Angular/Spring Boot应用时请求转发失败问题排查
我正在尝试将Angular应用与Spring Boot应用进行Docker化部署,并配置PostgreSQL数据库。所有组件已搭建完成,但发现Angular应用无法解析backend:8081地址,所有请求均返回ERR_NAME_NOT_RESOLVED错误,尽管容器间ping通信正常。
相关配置
Spring Boot应用Dockerfile
# Use a base image with JDK and Maven installed FROM maven:3.8.4-openjdk-17-slim AS build # Set the working directory WORKDIR /app # Copy the pom.xml file to the working directory COPY pom.xml . # Copy the entire project to the working directory COPY src ./src # Build the application with Maven RUN mvn clean package -DskipTests # Use a smaller base image for the runtime environment FROM amazoncorretto:17-alpine-jdk # Set the working directory WORKDIR /app # Copy the built JAR file from the build stage to the runtime image COPY --from=build /app/target/restaurant.jar ./app.jar RUN mkdir /app/storage # Expose the port that your Spring Boot application listens on (if applicable) EXPOSE 8081 # Command to run the application CMD ["java", "-jar", "app.jar"]
application.properties配置
spring.datasource.url=${DB_URL} spring.datasource.username=${DB_USERNAME} spring.datasource.password=${DB_PASSWD} # Hibernate settings spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect spring.jpa.hibernate.ddl-auto=update # Application's server port #server.port=8081 server.port=${SERVER_PORT} spring.servlet.multipart.max-file-size=5GB spring.servlet.multipart.max-request-size=5GB files.folder=${STORAGE} front.address=${FRONT_ADDR} # Application's name spring.application.name=NapolitanaBack
CORS配置类
package com.napolitana.restaurant.config; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class CorsConfig { @Value("${front.address}") String frontAddress; @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurer() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins(frontAddress) //.allowedOrigins("*") .allowedMethods("GET", "POST", "PUT", "DELETE", "PATCH") .allowedHeaders("*"); } }; } }
Angular应用Dockerfile
# Base image with Node.js installed FROM node:18.20.2 AS build # Set the working directory WORKDIR /app # Copy package.json and package-lock.json (if present) to the working directory COPY package.json package-lock.json ./ # Install dependencies RUN npm install # Copy the entire project to the working directory COPY . . # Build the Angular app for production RUN npm run build --prod # Use NGINX base image for serving Angular application FROM nginx:alpine # Copy build artifacts from the build stage to NGINX public directory COPY --from=build /app/dist/napolitana-front /usr/share/nginx/html # Copy nginx.conf to configure the server COPY default.conf /etc/nginx/conf.d/default.conf # Expose the port that NGINX listens on EXPOSE 80 # Command to start NGINX and serve the Angular app CMD ["nginx", "-g", "daemon off;"]
Nginx的default.conf配置
server { listen 80; server_name frontend; location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://backend:8081; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; } location /admin/ { alias /usr/share/nginx/html; index index.html; try_files $uri $uri/ /admin/index.html; } location ~ ^/admin/([a-zA-Z0-9\-_]+)/(.*)$ { alias /usr/share/nginx/html/admin/$1/; index index.html; try_files $uri $uri/ /admin/$1/index.html; } }
Angular环境配置
export const environment = { BASE_URL: 'http://backend:8081/api' }
docker-compose.yml配置
version: '3.8' services: postgres: image: postgres:latest restart: always environment: POSTGRES_DB: napolitana POSTGRES_USER: gduser POSTGRES_PASSWORD: gduser volumes: - postgres_data:/var/lib/postgresql/data networks: - napolitana-network backend: build: context: ./NapolitanaBack dockerfile: Dockerfile image: backend-image:latest ports: - "8081:8081" volumes: - C:\Users\mr\Desktop\storage:/app/storage # Bind mount to local folder for shared data environment: - DB_URL=jdbc:postgresql://postgres:5432/napolitana - DB_USERNAME=gduser - DB_PASSWD=gduser - SERVER_PORT=8081 - STORAGE=/app/storage - FRONT_ADDR=http://frontend:80 depends_on: - postgres networks: - napolitana-network frontend: build: context: ./NapolitanaFront dockerfile: Dockerfile image: frontend-image:latest ports: - "80:80" # Map port 80 of the container to port 80 of the host volumes: - C:\Users\mr\Desktop\storage:/usr/share/nginx/html/assets/storage # Bind mount to local folder for shared data depends_on: - backend # Ensure backend service starts first networks: - napolitana-network volumes: postgres_data: networks: napolitana-network:
核心原因
浏览器运行在宿主机的网络环境中,而非Docker内部的napolitana-network网络,因此无法识别Docker Compose定义的backend服务域名(该域名仅在Docker内部网络可解析)。当前Angular的BASE_URL直接指向http://backend:8081/api,浏览器会尝试在本地DNS查找backend,必然失败。
此外,虽然你配置了Nginx反向代理规则,但前端并未利用该代理,而是直接请求后端服务,完全绕开了Nginx的转发逻辑。
解决方案
1. 修改Angular环境配置,利用Nginx代理
将Angular的环境配置改为相对路径,让请求发送到当前前端所在域名(即Nginx的宿主机80端口),再由Nginx转发到后端:
export const environment = { BASE_URL: '/api' }
2. 调整Nginx反向代理路径(确保逻辑正确)
检查/api/的转发规则:如果Spring Boot接口本身带有/api前缀,当前配置无需修改;如果接口无前缀,需给proxy_pass末尾添加斜杠,避免路径拼接错误:
location /api/ { proxy_pass http://backend:8081/; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; }
3. 修正CORS配置(可选,避免后续跨域问题)
现在前端通过Nginx代理请求后端,浏览器会认为是同域名请求,CORS规则不再生效。但如果后续有直接访问后端的场景,可将FRONT_ADDR改为宿主机地址(如http://localhost:80),或保留http://frontend:80(供Docker内部通信使用),确保Spring Boot的CORS配置允许该来源。
4. 重新构建并启动服务
修改配置后,需重新构建前端镜像并重启所有服务:
docker-compose down docker-compose build frontend docker-compose up -d
内容的提问来源于stack exchange,提问作者Ramez wechteti

