在Dorado的运行过程中动态装载数据、提交数据、执行AjaxAction、执行远程数据校验等动作都会发起Ajax类请求。由于此类请求对于返回数据的格式有着严格的要求,无论Server的逻辑成否都必须确保向Client返回特定格式的数据。因此通常不会使用ErrorPage机制。
要统一的处理Ajax类请求中的异常应利用Dorado提供的全局拦截器机制,见 定义各种全局拦截器。
很容易想象的是我们应该如何在这些拦截器中记录日志、改变传向客户端的异常信息。可是当我们一旦需要实现类似于普通请求中的出错重定向功能时应该怎么做呢?必须一旦业务系统抛出用户未登录或Session超时的异常时,即使在Ajax类请求中发生了这样的错误,开发者也仍然可能希望界面能够自动跳转到登录页面。
为解决这一问题,Dorado提供了一种特别的异常类com.bstek.dorado.view.resolver.ClientRunnableException。该异常类的作用是向Client端返回一段可执行的JavaScript脚本,当Dorado的客户端接收到这段脚本后会自动的执行它。
public class AjaxServiceInterceptor extends PatternMethodInterceptor { public Object invoke(MethodInvocation methodInvocation) throws Throwable { try { return methodInvocation.proceed(); } catch (AuthenticationException e) { StringBuffer script = new StringBuffer(); script.append("dorado.MessageBox.prompt('User not logged in or session expired!\\n") .append("Do you wanna go to the login page?', function() {") .append("open($url('>Login.d'), '_self');") .append("});"); throw new ClientRunnableException(script.toString()); } } }
根据Dorado的AjaxEngine实现的规范,当其接收到content-type为text/runnable的Response时,会自动将Response的内容识别为JavaScript并立即执行它。
不过,由于Dorado中的Ajax请求支持请求自动合并的功能(一种自动将连续发出的Ajax请求合并为一次HTTP请求的优化功能),在这种合并请求中问题会变得比较复杂。因此,通常我们不建议你不要直接设置Response的content-type或者直接向Response的outputStream中进行输出。而是利用上面提到的ClientRunnableException这类经过包装方法。
由于返回一段可执行的JavaScript会打破AjaxAction等Ajax操作在客户端的正常后续处理,因此Dorado将此操作视为失败的Ajax调用,在这种情况下AjaxAction的onSuccess事件不会被触发,相反onFailure事件会在执行的JavaScript被真正的执行前触发。