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

Spring Boot下400 BAD REQUEST响应的CORS问题:无法读取响应体

Spring Boot返回400 BAD REQUEST时React客户端无法读取响应体

问题分析

核心问题在于:Spring Boot返回400状态码时,React客户端无法读取响应体,但Postman和服务器日志均确认响应体已正确发送,且200状态的请求可正常读取内容。这主要是因为fetch API对非2xx状态码的响应处理逻辑特殊,且当前代码未在错误分支中手动解析响应内容。

解决方案

1. 修改React客户端代码,手动解析错误响应体

fetch在响应状态码非2xx时会进入catch分支,但传入的error是Response对象而非普通Error实例,必须手动调用json()或text()方法读取响应体:

fetch(`${API_ROOT}/xxx/schedule`, {
  method: "POST",
  body: postData,
  headers: {
    Authorization: `Bearer ${context.user.token}`,
    "Content-Type": "application/json",
  },
})
  .then(function (response) {
    console.log(response);
    if (!response.ok) {
      throw response;
    }
    return response.json();
  })
  .then(function (text) {
    console.log(text);
    toast.success("New record is added successfully.");
  })
  .catch(async function (error) {        
    let errorMsg = 'Unknown error';
    // 区分处理Response对象和普通Error
    if (error instanceof Response) {
      try {
        const errorBody = await error.json();
        errorMsg = errorBody.message || `Request failed with status ${error.status}`;
      } catch (e) {
        // 响应非JSON格式时读取文本内容
        const errorText = await error.text();
        errorMsg = errorText || `Request failed with status ${error.status}`;
      }
    } else {
      errorMsg = error.message;
    }
    toast.error(
      <div>
        Error adding Schedule. <br />
        {errorMsg}
      </div>
    );
    console.log(["Error adding Schedule.", errorMsg]);
  });

2. 确保Spring Boot的CORS配置覆盖错误响应

验证全局CORS配置能处理所有响应(包括异常返回的400响应):

方式一:使用WebMvcConfigurer配置

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("http://localhost:3000")
                .allowedMethods("PUT", "GET", "HEAD", "POST", "DELETE", "OPTIONS")
                .allowedHeaders("authorization", "content-type")
                .allowCredentials(true)
                .maxAge(1800);
    }
}

方式二:使用过滤器配置(优先级更高)

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;

        response.setHeader("Access-Control-Allow-Origin", "http://localhost:3000");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "PUT, GET, HEAD, POST, DELETE, OPTIONS");
        response.setHeader("Access-Control-Allow-Headers", "authorization, content-type");
        response.setHeader("Access-Control-Max-Age", "1800");

        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, res);
        }
    }

    @Override
    public void init(FilterConfig filterConfig) {}

    @Override
    public void destroy() {}
}

3. 检查服务器异常处理逻辑

确保Spring Boot返回400响应时正确写入响应体,无流关闭导致的内容丢失:

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ErrorResponse> handleValidationExceptions(MethodArgumentNotValidException ex) {
        ErrorResponse errorResponse = new ErrorResponse();
        errorResponse.setMessage("Validation failed");
        ex.getBindingResult().getAllErrors().forEach((error) -> {
            String errorMessage = error.getDefaultMessage();
            errorResponse.addDetail(errorMessage);
        });
        return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST);
    }

    // 其他异常处理逻辑...
}

关键说明

  • fetch仅在网络错误时抛出普通Error,HTTP错误(如400、500)会返回正常Response对象,需手动判断response.ok并处理。
  • 若浏览器Network面板中Response为空,需检查服务器是否真的发送了内容,或是否存在中间代理(如Nginx)截断响应。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 04:17:14