Apache反向代理虚拟主机配置问题:API调用先404后返回403
问题分析与解决方案
核心问题1:多虚拟主机导致的404错误
你配置了两个监听*:81的<VirtualHost>但未指定ServerName,Apache会默认仅加载第一个虚拟主机配置,所有请求(包括/be路径)都会被转发到React的localhost:3000,而React应用不存在/be相关接口,因此返回404。
修正Apache代理配置
无需创建多个虚拟主机,在同一个<VirtualHost>中配置多路径转发即可:
<VirtualHost *:81> # 前端React应用:根路径转发到3000端口 ProxyPass / http://localhost:3000/ ProxyPassReverse / http://localhost:3000/ # 后端SpringBoot应用:/be/路径转发到8080端口 # 注意路径末尾的斜杠,避免路径拼接错误 ProxyPass /be/ http://localhost:8080/ ProxyPassReverse /be/ http://localhost:8080/ </VirtualHost>
配置完成后重启Apache,此时http://localhost:81会访问前端,http://localhost:81/be/xxx会转发到后端的http://localhost:8080/xxx接口。
核心问题2:命名虚拟主机后的403错误
403是Spring Security的权限拦截导致,通常和跨域(CORS)、预检请求(OPTIONS)或凭证传递配置有关。
1. 配置SpringBoot跨域支持
允许前端域名(http://localhost:81)携带凭证访问后端,避免跨域拦截:
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("http://localhost:81") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .allowCredentials(true) // 允许携带Cookie(JSESSIONID) .maxAge(3600); } }
2. 调整Spring Security配置
放行OPTIONS预检请求,启用CORS并配置基础认证:
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .cors().and() // 关联上面的CORS配置 .csrf().disable() // 若不需要CSRF防护可禁用,或按需配置令牌传递 .authorizeRequests() .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() // 放行预检请求 .antMatchers("/login").permitAll() // 放行登录接口 .anyRequest().authenticated() .and() .httpBasic(); // 启用基础认证 } }
3. 完善后端会话配置
确保JSESSIONID的Cookie能跨路径传递,在application.properties中添加:
server.forward-headers-strategy=NATIVE server.servlet.session.cookie.domain=localhost server.servlet.session.cookie.path=/
4. 前端Axios配置
开启凭证携带,确保JSESSIONID能被正确传递:
// 全局配置 axios.defaults.withCredentials = true; // 登录请求示例 axios.post('http://localhost:81/be/login', {}, { auth: { username: 'your-username', password: 'your-password' } }) .then(res => { // 此时浏览器已自动存储JSESSIONID Cookie }) .catch(err => console.error(err));
内容的提问来源于stack exchange,提问作者DottorPuce
相关产品推荐
相关产品推荐

