Spring Controller处理Ajax请求返回错误信息的最佳实践与异常处理
Spring Controller处理Ajax请求返回错误信息的最佳实践
嘿,针对你在Spring Controller处理Ajax调用时返回错误信息的问题,我来分享几个实用的最佳实践,尤其是适配你当前手动构建JSON的场景:
1. 告别手动拼接JSON,用POJO自动序列化
你现在手动用JSONObject/JSONArray拼接字符串返回,虽然能实现功能,但Spring其实提供了更简洁、易维护的方式——定义一个通用的响应实体类,让Spring帮你自动序列化为JSON。这样不仅代码更干净,还能统一响应格式,方便前端处理。
比如先定义一个通用响应类:
public class ApiResponse<T> { private int code; // 自定义状态码,比如200成功,500错误 private String message; // 提示信息 private T data; // 返回的业务数据 // 构造器、getter、setter省略 // 静态工厂方法,简化创建 public static <T> ApiResponse<T> success(T data) { ApiResponse<T> response = new ApiResponse<>(); response.setCode(200); response.setMessage("操作成功"); response.setData(data); return response; } public static <T> ApiResponse<T> error(int code, String message) { ApiResponse<T> response = new ApiResponse<>(); response.setCode(code); response.setMessage(message); return response; } }
然后在你的Controller里直接返回这个类的实例,Spring会自动转成JSON:
@RequestMapping(value = "getValue") public @ResponseBody ApiResponse<JSONObject> getValue() { try { JSONObject jsonObject = new JSONObject(); JSONArray jsonArray = new JSONArray(); jsonObject.put("mykey", jsonArray); return ApiResponse.success(jsonObject); } catch (Exception e) { // 生产环境建议不要直接返回异常详情,而是打日志+返回友好提示 return ApiResponse.error(500, "处理失败:" + e.getMessage()); } }
2. 全局异常处理,避免重复try-catch
如果每个Controller方法都写try-catch会非常繁琐,而且代码冗余。你可以用@ControllerAdvice配合@ExceptionHandler实现全局异常处理,让所有Controller的异常都被统一捕获处理。
示例代码:
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; @ControllerAdvice public class GlobalExceptionHandler { private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class); // 捕获所有通用异常 @ExceptionHandler(Exception.class) @ResponseBody public ApiResponse<Void> handleGeneralException(Exception e) { // 打日志记录异常详情,方便排查问题 log.error("请求处理发生异常", e); // 返回用户友好的提示,不要暴露内部异常信息 return ApiResponse.error(500, "服务器内部错误,请稍后重试"); } // 可以针对特定异常单独处理,比如参数错误 @ExceptionHandler(IllegalArgumentException.class) @ResponseBody public ApiResponse<Void> handleIllegalArgException(IllegalArgumentException e) { return ApiResponse.error(400, "参数错误:" + e.getMessage()); } }
这样你的Controller方法就可以不用写try-catch,专注于业务逻辑:
@RequestMapping(value = "getValue") public @ResponseBody ApiResponse<JSONObject> getValue() { JSONObject jsonObject = new JSONObject(); JSONArray jsonArray = new JSONArray(); jsonObject.put("mykey", jsonArray); // 如果这里抛出异常,全局处理器会自动接手处理 return ApiResponse.success(jsonObject); }
3. 用ResponseEntity灵活控制HTTP状态码
如果你需要让前端通过HTTP状态码快速判断请求结果(比如400表示参数错误,500表示服务器错误),可以用ResponseEntity代替@ResponseBody,它能同时控制响应体和HTTP状态码。
示例:
import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RequestMapping(value = "getValue") public ResponseEntity<ApiResponse<JSONObject>> getValue() { try { JSONObject jsonObject = new JSONObject(); JSONArray jsonArray = new JSONArray(); jsonObject.put("mykey", jsonArray); return ResponseEntity.ok(ApiResponse.success(jsonObject)); } catch (IllegalArgumentException e) { // 返回400 Bad Request状态码 return ResponseEntity.badRequest().body(ApiResponse.error(400, e.getMessage())); } catch (Exception e) { log.error("处理失败", e); // 返回500 Internal Server Error状态码 return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body(ApiResponse.error(500, "服务器内部错误")); } }
临时方案:如果暂时不想重构代码
如果你暂时不想改成POJO的方式,也可以在try-catch里直接构建错误的JSON字符串返回:
@RequestMapping(value = "getValue") public @ResponseBody String getValue(){ try { JSONObject jsonObject = new JSONObject(); JSONArray jsonArray = new JSONArray(); jsonObject.put("mykey",jsonArray); return jsonObject.toString(); } catch (Exception e) { JSONObject errorJson = new JSONObject(); errorJson.put("code", 500); errorJson.put("message", "处理失败:" + e.getMessage()); return errorJson.toString(); } }
不过还是推荐用POJO+全局异常处理的方式,更利于长期维护。
总结一下核心最佳实践
- 优先使用通用响应POJO配合
@ResponseBody,避免手动拼接JSON,减少出错概率 - 用全局异常处理器统一处理异常,减少代码冗余,提升可维护性
- 用ResponseEntity灵活控制HTTP状态码,让前后端交互更规范
- 生产环境不要直接返回异常栈信息,要通过日志记录详情,返回用户友好的提示
内容的提问来源于stack exchange,提问作者Mamun Kayum




