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

Primefaces Extensions Document Viewer后端异常前端处理咨询

问题:PrimeFaces Extensions DocumentViewer 异常处理优化方案

场景说明

我使用PrimeFaces Extensions 12的documentViewer组件,前端代码如下:

<pe:documentViewer zoom="page-fit" pagemode="thumbs"
                   id="iframeViewPdf" width="80%" height="800"          
                   url="/pdfServlet?id=#{param.id}"/>

后端通过Spring MVC控制器输出PDF字节流,代码如下:

@RequestMapping(value = "/pdfServlet")
public void doGet(HttpServletRequest request, HttpServletResponse response) throws Exception {
    InputStream inputStream = null;
    OutputStream outputStream = null;
    try{
        String documentId = request.getParameter("id");
        inputStream = myRepository.getFileAsInputStream(documentId);
        outputStream = response.getOutputStream();
        IOUtils.copy(inputStream, outputStream);
        
    }catch(Exception e){
        // 以下操作均无效
        // request.getRequestDispatcher(request.getContextPath() + "/error").forward(request, response);
        // response.sendRedirect(request.getContextPath() + "/error");
        // throw e;
        // 如何实现跳转到错误页或在页面显示错误提示?
    }finally{
        IOUtils.closeQuietly(inputStream);
        IOUtils.closeQuietly(outputStream);
    }
}

当前问题

正常场景下代码运行正常,但后端发生异常时,前端无法正确处理:

  • 直接抛出异常无效果
  • 尝试重定向/转发到错误页时,始终提示"无法在响应提交后转发/重定向"
  • 应用已配置全局异常跳转,但对该场景无效

更新信息

后端加载异常时,Viewer会显示错误响应(截图如下),想知道能否通过JavaScript处理这种情况:
DocumentViewer异常显示效果


优化方案

方案1:后端提前校验,避免响应提交后处理异常

在写入输出流前完成所有校验逻辑,确保不会在流操作后抛出异常,同时规范响应头设置:

@RequestMapping(value = "/pdfServlet")
public void doGet(HttpServletRequest request, HttpServletResponse response) throws Exception {
    InputStream inputStream = null;
    OutputStream outputStream = null;
    try {
        String documentId = request.getParameter("id");
        
        // 提前校验文档存在性、权限等
        if (documentId == null || !myRepository.exists(documentId)) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND, "文档不存在");
            return;
        }
        
        // 设置正确的响应头,确保浏览器正确解析内容
        response.setContentType("application/pdf");
        response.setHeader("Content-Disposition", "inline; filename=\"document.pdf\"");
        
        inputStream = myRepository.getFileAsInputStream(documentId);
        outputStream = response.getOutputStream();
        IOUtils.copy(inputStream, outputStream);
        outputStream.flush();
    } catch (Exception e) {
        // 仅在响应未提交时处理异常
        if (!response.isCommitted()) {
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "加载文档失败");
        }
    } finally {
        IOUtils.closeQuietly(inputStream);
        IOUtils.closeQuietly(outputStream);
    }
}

核心要点:

  • 前置校验避免流操作后报错
  • 设置规范的响应头,防止异常时浏览器解析混乱
  • 仅在响应未提交时发送错误状态码

方案2:前端通过JS监听DocumentViewer加载状态

documentViewer本质是iframe,可通过监听其加载事件判断响应是否正常,结合AJAX提前校验文档可用性:

<pe:documentViewer zoom="page-fit" pagemode="thumbs"
                   id="iframeViewPdf" width="80%" height="800"          
                   url="/pdfServlet?id=#{param.id}"/>

<script>
$(function() {
    const iframe = document.getElementById('iframeViewPdf');
    iframe.addEventListener('load', function() {
        try {
            // 校验iframe内容类型是否为PDF
            const contentType = iframe.contentDocument.contentType;
            if (contentType !== 'application/pdf') {
                showError('文档加载失败,请检查文档状态');
            }
        } catch (e) {
            // 跨域场景下无法访问iframe内容,通过AJAX提前校验
            checkDocumentStatus(#{param.id});
        }
    });
});

function checkDocumentStatus(docId) {
    $.ajax({
        url: '/checkDocument',
        data: {id: docId},
        success: function(res) {
            if (!res.success) {
                showError(res.message || '文档加载失败');
            }
        },
        error: function() {
            showError('网络异常,无法加载文档');
        }
    });
}

function showError(msg) {
    $('#errorContainer').text(msg).show();
    $('#iframeViewPdf').hide();
}
</script>

<!-- 错误提示容器 -->
<div id="errorContainer" style="display:none; color:#dc3545; font-size:18px; padding:20px;"></div>

核心要点:

  • 监听iframe的load事件判断内容有效性
  • 跨域场景下用AJAX前置校验文档状态
  • 显示错误提示并隐藏异常的Viewer组件

方案3:全局异常处理器配合自定义错误响应

配置Spring MVC全局异常处理器,针对PDF请求返回纯文本错误而非跳转页面:

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public void handlePdfException(HttpServletRequest request, HttpServletResponse response, Exception e) throws IOException {
        if (!response.isCommitted()) {
            String requestUri = request.getRequestURI();
            // 判断是否为PDF加载请求
            if (requestUri.contains("/pdfServlet")) {
                response.setContentType("text/plain");
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                response.getWriter().write("文档加载失败:" + e.getMessage());
            } else {
                // 其他请求跳转到全局错误页
                response.sendRedirect(request.getContextPath() + "/error");
            }
        }
    }
}

核心要点:

  • 用@ControllerAdvice统一处理异常
  • 针对PDF请求返回纯文本错误,避免跳转导致的响应提交异常
  • 仅处理未提交的响应

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 12:50:26