基于Spring的RestControllerAdvice按sourceid头路由至对应异常处理器
问题
我们开发了一个服务于不同部门的API,但4xx或5xx错误响应体格式需遵循各部门要求,无法自主决定。所幸不同部门的请求带有不同的sourceid HTTP请求头。请问基于Spring的ExceptionHandler和RestControllerAdvice机制,能否根据请求中的sourceid头将异常路由至对应的ExceptionHandler,以返回符合预期格式的响应?
回答
完全可以实现,基于Spring的RestControllerAdvice和ExceptionHandler机制,有两种常用的实现思路:
方案一:多ExceptionHandler方法匹配特定sourceid
通过在ExceptionHandler方法中绑定sourceid请求头,让Spring自动匹配符合条件的处理方法。如果请求头不匹配,Spring会自动尝试其他兼容的ExceptionHandler方法。
示例代码:
@RestControllerAdvice public class GlobalExceptionHandler { // 处理sourceid为deptA的请求异常 @ExceptionHandler(Exception.class) public ResponseEntity<DeptAErrorResponse> handleDeptAException(Exception e, @RequestHeader("sourceid") String sourceid) { if (!"deptA".equals(sourceid)) { throw new IllegalStateException("不匹配的sourceid"); } // 构造符合deptA格式的错误响应 DeptAErrorResponse response = new DeptAErrorResponse(); response.setCode("A-500"); response.setMsg(e.getMessage()); return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR); } // 处理sourceid为deptB的请求异常 @ExceptionHandler(Exception.class) public ResponseEntity<DeptBErrorResponse> handleDeptBException(Exception e, @RequestHeader("sourceid") String sourceid) { if (!"deptB".equals(sourceid)) { throw new IllegalStateException("不匹配的sourceid"); } // 构造符合deptB格式的错误响应 DeptBErrorResponse response = new DeptBErrorResponse(); response.setErrorId(UUID.randomUUID().toString()); response.setErrorMessage(e.getMessage()); response.setTimestamp(System.currentTimeMillis()); return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR); } // 默认处理逻辑(当sourceid不存在或不匹配时) @ExceptionHandler(Exception.class) public ResponseEntity<DefaultErrorResponse> handleDefaultException(Exception e) { DefaultErrorResponse response = new DefaultErrorResponse(); response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); response.setMessage(e.getMessage()); return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR); } }
方案二:单一ExceptionHandler分支处理
在全局异常处理类中注入HttpServletRequest,获取sourceid后通过分支逻辑调用对应部门的错误响应构造方法。这种方式更适合部门较多的场景,便于统一维护路由规则。
示例代码:
@RestControllerAdvice public class GlobalExceptionHandler { @Autowired private HttpServletRequest request; @ExceptionHandler(Exception.class) public ResponseEntity<?> handleException(Exception e) { String sourceid = request.getHeader("sourceid"); switch (sourceid) { case "deptA": return buildDeptAResponse(e); case "deptB": return buildDeptBResponse(e); // 可扩展更多部门分支 default: return buildDefaultResponse(e); } } private ResponseEntity<DeptAErrorResponse> buildDeptAResponse(Exception e) { DeptAErrorResponse response = new DeptAErrorResponse(); response.setCode("A-" + HttpStatus.INTERNAL_SERVER_ERROR.value()); response.setMessage(e.getMessage()); return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR); } private ResponseEntity<DeptBErrorResponse> buildDeptBResponse(Exception e) { DeptBErrorResponse response = new DeptBErrorResponse(); response.setErrorDetails(e.getMessage()); response.setErrorCode(HttpStatus.INTERNAL_SERVER_ERROR.value()); response.setRequestId(request.getHeader("requestId")); return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR); } private ResponseEntity<DefaultErrorResponse> buildDefaultResponse(Exception e) { DefaultErrorResponse response = new DefaultErrorResponse(); response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); response.setMessage("服务器内部错误"); return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR); } }
两种方案都能满足根据sourceid路由异常处理逻辑的需求,你可以根据部门数量和维护成本选择合适的实现方式。
内容的提问来源于stack exchange,提问作者ildvzg68472
相关产品推荐
相关产品推荐

