如何连接Angular+Nginx Docker容器与Spring后端并解决CORS错误
CORS错误与Nginx 405错误排查与解决
问题描述
每次前端向服务器发起请求都遇到CORS错误。前端容器通过curl请求同网络的后端容器正常,本地运行容器也无问题。Postman测试时Nginx返回405错误,Spring后端未收到请求;Firefox中请求无法发送,仅返回CORS错误。
现有配置
Nginx default.conf配置
server { listen 80; sendfile on; default_type application/octet-stream; gzip on; gzip_http_version 1.1; gzip_disable "MSIE [1-6]\."; gzip_min_length 256; gzip_vary on; gzip_proxied expired no-cache no-store private auth; gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; gzip_comp_level 9; root /usr/share/nginx/html; location / { try_files $uri $uri/ /index.html =404; } }
Docker Compose配置
version: "3.5" services: backend: image: spring_backend container_name: spring build: context: ./ expose: - 8080 restart: always networks: - reverse-proxy frontend: image: angular_frontend container_name: angular build: https://github.com/some_repo/frontend.git ports: - "80:80" restart: always networks: - reverse-proxy networks: reverse-proxy: name: reverse-proxy
Angular环境配置
export const environment = { url: 'http://spring:8080/', production: true, };
Spring后端Security配置
@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { private final PersonDetailsService personDetailsService; private final JWTFilter jwtFilter; @Autowired public SecurityConfig(PersonDetailsService personDetailsService, JWTFilter jwtFilter){ this.personDetailsService = personDetailsService; this.jwtFilter = jwtFilter; } @SneakyThrows(Exception.class) protected void configure(HttpSecurity http) { http .csrf().disable() .cors().configurationSource(corsConfigurationSource()) .and() .authorizeRequests().antMatchers("/login","/register").permitAll() .anyRequest().hasAnyRole("USER") .and() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class); } @SneakyThrows(Exception.class) protected void configure(AuthenticationManagerBuilder auth) { auth.userDetailsService(personDetailsService); } @Bean public PasswordEncoder getPasswordEncoder(){ return new BCryptPasswordEncoder(); } @Bean @SneakyThrows(Exception.class) public AuthenticationManager authenticationManagerBean() { return super.authenticationManagerBean(); } @Bean CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.addAllowedOrigin("*"); configuration.addAllowedHeader("*"); configuration.addAllowedMethod("*"); configuration.addExposedHeader("*"); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; } }
问题分析与解决方案
核心问题
- 前端地址配置错误:Angular中使用
http://spring:8080/是Docker内部容器域名,浏览器无法解析该地址,实际请求会发送到前端Nginx的80端口,导致Nginx将API请求当作静态资源处理,返回index.html,引发405错误和CORS问题。 - Nginx未配置反向代理:当前Nginx仅处理前端静态文件,未将API请求转发到后端容器。
解决步骤
修改Angular环境配置
将后端地址改为相对路径,让请求先发送到前端Nginx:export const environment = { url: '/api/', production: true, };更新Nginx default.conf配置
添加反向代理规则,将/api/开头的请求转发到后端Spring容器:server { listen 80; sendfile on; default_type application/octet-stream; gzip on; gzip_http_version 1.1; gzip_disable "MSIE [1-6]\."; gzip_min_length 256; gzip_vary on; gzip_proxied expired no-cache no-store private auth; gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; gzip_comp_level 9; root /usr/share/nginx/html; # 反向代理后端API请求 location /api/ { proxy_pass http://spring:8080/; proxy_set_header Host $host; 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; } location / { try_files $uri $uri/ /index.html =404; } }验证后端CORS配置
后端已配置允许所有来源,通过Nginx反向代理后,请求Origin会是前端域名,后端配置可保持不变;若需更严谨,可将addAllowedOrigin("*")改为实际前端域名(如http://your-domain.com)。重建并重启容器
重新构建Angular镜像(因环境配置修改),再启动所有容器:docker-compose down docker-compose build frontend docker-compose up -d
额外说明
- 前端容器内curl能访问后端,是因为容器处于Docker内部网络可解析
spring域名,但浏览器运行在宿主机,无法识别该内部域名,必须通过Nginx转发。 - 405错误源于Nginx将API请求当作静态文件处理,配置反向代理后即可解决。
内容的提问来源于stack exchange,提问作者magik455
相关产品推荐
相关产品推荐

