You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中使用Fetch API无法捕获Spring Security返回的HTTP 401错误

嘿,我一眼就揪出问题的根源了——你设置的mode: "no-cors"正是导致你拿不到响应状态码、catch也完全不生效的罪魁祸首!

为什么mode: "no-cors"会搞砸一切?

当你开启这个模式时,浏览器会严格限制你对响应的访问权限:不管服务器返回什么状态码(包括401),你都没法读取response.status、响应内容这些关键信息;而且Fetch的catch块只会在网络层面出错(比如请求根本发不出去)时才触发,像401这种HTTP状态码错误,它会认为请求“成功完成”,自然不会走到catch里。

一步步解决问题:

1. 立刻移除mode: "no-cors"配置

直接删掉Fetch选项里的这行代码,浏览器默认会使用cors模式,这才允许你正常读取响应内容。但前提是你的Spring Security后端要配置好CORS,允许前端域名发起跨域请求。

2. 给Spring Security配置CORS支持

在你的Spring Security配置类里开启CORS,并设置允许的前端域名、请求方法等规则:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .cors() // 开启CORS支持
            .and()
            .authorizeRequests()
            // 这里放你的其他安全规则,比如允许登录接口匿名访问
            .antMatchers("/login").permitAll()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .loginProcessingUrl("/login");
    }

    // 配置具体的CORS规则
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration config = new CorsConfiguration();
        // 替换成你的前端域名,比如http://localhost:3000
        config.setAllowedOrigins(Arrays.asList("http://你的前端地址"));
        config.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS"));
        config.setAllowedHeaders(Arrays.asList("Content-Type"));
        config.setAllowCredentials(true); // 如果需要携带cookie的话开启

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return source;
    }
}

3. 修改前端Fetch代码,正确处理HTTP错误

Fetch不会自动把4xx/5xx状态码当成错误,所以你需要在第一个then里手动判断状态,把非2xx的状态转为错误,这样才能进入catch块处理:

login = (event) => {
  event.preventDefault();
  const data = {
    username: this.refs.username.value,
    password: this.refs.password.value
  };

  fetch('http://localhost:8080/login', {
    method: 'POST',
    body: JSON.stringify(data),
    headers: {
      'Content-Type': 'application/json'
    },
    credentials: 'include' // 如果需要携带认证相关cookie,加上这行
  })
  .then(response => {
    // 先判断状态是否在2xx成功范围内
    if (!response.ok) {
      // 抛出包含状态码的错误,方便后续处理
      return Promise.reject(new Error(`登录失败!状态码:${response.status}`));
    }
    return response;
  })
  .then(() => {
    console.log('Yeeee man, you can login');
    this.props.history.push('/');
  })
  .catch(error => {
    console.log('错误信息:', error.message);
    // 这里可以根据状态码做针对性提示,比如401就提示用户名或密码错误
  });
}

额外提醒

如果你的前端和后端是同域的(比如都在localhost:8080),那CORS配置可以省略;但如果是跨域(比如前端在3000端口,后端在8080),必须配置CORS,否则浏览器会直接拦截请求。

内容的提问来源于stack exchange,提问作者Daimon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:18:10