dubbo~全局异常拦截器的使用与设计缺陷

异常拦截器ExceptionMapper

在JAX-RS(Java API for RESTful Web Services)中,ExceptionMapper接口用于将Java异常映射到HTTP响应。通过实现ExceptionMapper接口,你可以自定义如何处理特定类型的异常,并生成相应的HTTP响应。

优先级和选择

当有多个ExceptionMapper可用于处理同一类型的异常时,JAX-RS会选择最具体的那个。例如,如果你有一个处理RuntimeException的ExceptionMapper和一个处理NullPointerException的ExceptionMapper,那么当抛出NullPointerException时,会选择处理NullPointerException的ExceptionMapper。

定义自定义异常

    public class UniqueException extends RuntimeException {

	public UniqueException(Throwable cause) {
		super(cause);
	}

	public UniqueException(String message) {
		super(message);
	}

	public UniqueException(String message, Throwable cause) {
		super(message, cause);
	}

}

实现ExceptionMapper

/**
 * 数据表约束异常处理器.
 *
 * @author lind
 * @date 2024/6/4 10:45
 * @since 1.0.0
 */
@Provider
public class DbViolationExceptionMapper implements ExceptionMapper<UniqueException> {

	@Override
	public Response toResponse(UniqueException exception) {

		return Response.status(Response.Status.BAD_REQUEST)
				.entity(MapUtil.builder().put("error", exception.getMessage()).build()).type(MediaType.APPLICATION_JSON)
				.encoding("utf-8").build();// 非200的请求,这个type无效,一直是text/plain

		/*
		 * return Response.status(Response.Status.OK)
		 * .entity(MapUtil.builder().put("error", exception.getMessage()).build())
		 * .type("application/json; charset=UTF-8").build();//
		 * 200的请求,是可以使用application/json的
		 *
		 */
	}

}

注册ExceptionMapper

在文件resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports添加内容

com.xx.exception.handler.DbViolationExceptionMapper

业务代码直接抛出异常

if (getCurrentUserId() == null || !getCurrentUserId().equals(userId)) {
	throw new UniqueException("权限不足");
 }

相关问题

  • 当在ExceptionMapper中返回的Response对象,状态码为200时,可以响应为application/json
  • 当Response对象状态码非200时,响应一直是text/plain

经过调试与排查,发现当非200时,在这个过滤器里,它出现了两个content-type,text/plain不知道是什么时间被加进去的,如图

方法执行到这里时,为响应头添加了text/plain

setStatus()方法如下

  public void setStatus(int status) {
        if (status > 200) {
            this.addOutputHeaders(RestHeaderEnum.CONTENT_TYPE.getHeader(), MediaType.TEXT_PLAIN.value);
        }

        this.status = status;
    }

这也是业务代码中,直接报出自定义异常,在ExceptionMapper捕获返回json没有生效的原因,这块感觉dubbo设计的不太好。