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

Vaadin 23异步异常无法被ExceptionHandler捕获的解决方法咨询

问题描述

我有一个基础的ExceptionHandler视图,代码如下:

@ParentLayout(MainLayout.class)
@AnonymousAllowed
public class ExceptionHandler extends VerticalLayout implements HasErrorParameter<Exception> {

    static final Logger logger = LoggerFactory.getLogger(ExceptionHandler.class);

    @Override
    public int setErrorParameter(BeforeEnterEvent event, ErrorParameter<Exception> parameter) {

        logger.error("Error", parameter.getException());

        Label label = new Label(parameter.getException().getMessage());
        add(label);

        return HttpServletResponse.SC_NOT_FOUND;
    }

}

该视图在同步调用发生错误时可正常工作,但使用@Async特性时(示例代码如下),抛出的AsyncException无法被该ExceptionHandler捕获,仅能记录日志。请问如何正确抛出异常以使其被ExceptionHandler捕获?

异步调用代码:

ListenableFuture<DecisionMatrixPage> listenableFuture = container.queryDataAsync();
var ui = UI.getCurrent();
listenableFuture.addCallback(page -> {

    ui.access(() -> {
        //do something
    });

}, err -> {
    logger.error("Error", err);
    throw new AsyncException("Async error", err);
});
解决方案

异步操作抛出的异常无法直接触发HasErrorParameter的处理逻辑,因为异步回调运行在独立线程中,不属于Vaadin的导航或请求处理流程。要让ExceptionHandler捕获到异步异常,需要手动将异常关联到当前UI的错误处理机制,具体可采用以下几种方式:

  • 在UI.access中触发错误视图导航
    不要在异步回调中直接抛出异常,而是在ui.access内部通过导航到ExceptionHandler视图来传递异常信息:

    listenableFuture.addCallback(page -> {
        ui.access(() -> {
            // 处理正常逻辑
        });
    }, err -> {
        logger.error("Error", err);
        ui.access(() -> {
            // 携带异常信息导航到错误视图
            AsyncException asyncEx = new AsyncException("Async error", err);
            RouteParameters params = new RouteParameters("errorMsg", asyncEx.getMessage());
            UI.getCurrent().navigate(ExceptionHandler.class, params);
        });
    });
    
  • 扩展ExceptionHandler支持路由参数
    修改ExceptionHandler,使其既能处理同步错误,也能接收异步传递的异常信息:

    @Route(value = "error", layout = MainLayout.class)
    @AnonymousAllowed
    public class ExceptionHandler extends VerticalLayout implements HasErrorParameter<Exception>, HasUrlParameter<String> {
    
        static final Logger logger = LoggerFactory.getLogger(ExceptionHandler.class);
        private String asyncErrorMsg;
    
        @Override
        public void setParameter(BeforeEvent event, @OptionalParameter String errorMsg) {
            this.asyncErrorMsg = errorMsg;
        }
    
        @Override
        public int setErrorParameter(BeforeEnterEvent event, ErrorParameter<Exception> parameter) {
            String displayMsg = asyncErrorMsg != null ? asyncErrorMsg : parameter.getException().getMessage();
            Throwable logEx = asyncErrorMsg != null ? new AsyncException(asyncErrorMsg) : parameter.getException();
            
            logger.error("Error occurred", logEx);
            add(new Label(displayMsg));
            
            return HttpServletResponse.SC_NOT_FOUND;
        }
    }
    
  • 利用UI全局ErrorHandler捕获异常
    给当前UI设置全局ErrorHandler,捕获异步线程抛出的异常后再导航到错误视图:

    // 在UI初始化阶段设置全局错误处理器
    UI.getCurrent().setErrorHandler(errorEvent -> {
        Throwable ex = errorEvent.getThrowable();
        if (ex instanceof AsyncException) {
            UI.getCurrent().access(() -> 
                UI.getCurrent().navigate(ExceptionHandler.class)
            );
        }
    });
    
    // 异步回调中在ui.access内抛出异常,由全局ErrorHandler捕获
    listenableFuture.addCallback(page -> {
        ui.access(() -> {
            // 正常逻辑处理
        });
    }, err -> {
        logger.error("Error", err);
        ui.access(() -> {
            throw new AsyncException("Async error", err);
        });
    });
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 14:25:19