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
相关产品推荐
相关产品推荐

