All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cc.shacocloud.mirage.web.HandlerExecutionChain Maven / Gradle / Ivy

package cc.shacocloud.mirage.web;

import cc.shacocloud.mirage.utils.FutureUtils;
import cc.shacocloud.mirage.web.exception.HttpRequestBindingException;
import cc.shacocloud.mirage.web.http.MediaType;
import cc.shacocloud.mirage.web.util.RoutingContextUtils;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.buffer.Buffer;
import lombok.Setter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jetbrains.annotations.Nullable;
import org.springframework.core.log.LogFormatUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 请求响应处理器
 * 

* 为整个请求响应出入口的处理器类 */ public class HandlerExecutionChain { private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class); private final VertxInvokeHandler invokeHandler; @Nullable private Set mediaTypes; @Nullable private List interceptors; @Setter @Nullable protected HandlerExceptionResolverComposite exceptionResolverComposite; public static final Buffer EMPTY = Buffer.buffer(Unpooled.EMPTY_BUFFER); public HandlerExecutionChain(VertxInvokeHandler invokeHandler, RequestMappingInfo requestMapping, @Nullable HandlerInterceptorComposite interceptorComposite) { this.invokeHandler = invokeHandler; if (interceptorComposite != null) { this.interceptors = interceptorComposite.match(requestMapping.getPaths()); } String[] produces = requestMapping.getProduces(); if (!ObjectUtils.isEmpty(produces)) { this.mediaTypes = new HashSet<>(MediaType.parseMediaTypes(Arrays.asList(produces))); } } /** * 处理请求,请求的入口方法 * * @param ctx 请求上下文 */ public void handle(io.vertx.ext.web.RoutingContext ctx) { RoutingContext routingContext = createVertXRoutingContext(ctx); routingContext.put(RoutingContext.RECEIVE_REQUEST_TIME, System.currentTimeMillis()); if (logger.isDebugEnabled()) { logger.debug("路由器收到待处理请求:" + routingContext.normalisedPath()); logger.debug("当前请求实际绑定的处理器方法:" + this.invokeHandler); } if (!CollectionUtils.isEmpty(mediaTypes)) { routingContext.put(VertxInvokeHandler.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes); } HttpRequest request = routingContext.request(); HttpResponse response = routingContext.response(); AtomicInteger interceptorIndex = new AtomicInteger(0); // 注册响应释放后的处理 ctx.addEndHandler(res -> triggerAfterCompletion(request, response, interceptorIndex, res.cause())); try { // 执行拦截器的 preHandle 方法 applyPreHandle(request, response, interceptorIndex) .compose(goOn -> { if (goOn) { // 如果拦截器返回true则继续调用具体方法 return invokeHandler.invokeAndHandleRoutingContext(routingContext); } return Future.succeededFuture(); }) .onFailure(cause -> processExceptionHandler(request, response, cause)) .onSuccess(res -> processResult(request, response, res)); } catch (Exception e) { processExceptionHandler(request, response, e); } } /** * 委派给 {@link #processExceptionHandler} 方法执行,用于{@link io.vertx.ext.web.Route#failureHandler(Handler)}方法使用 */ void processException(io.vertx.ext.web.RoutingContext ctx) { RoutingContext routingContext = createVertXRoutingContext(ctx); processExceptionHandler(routingContext.request(), routingContext.response(), ctx.failure()); } /** * 处理异常情况 */ void processExceptionHandler(HttpRequest request, HttpResponse response, Throwable cause) { if (logger.isDebugEnabled()) { logger.debug("请求 '" + request.context().normalisedPath() + "' 处理发生例外,进行异常解析处理逻辑...", cause); } Future resFuture; if (this.exceptionResolverComposite != null) { resFuture = this.exceptionResolverComposite.resolveException(request, response, this.invokeHandler, cause) .compose(res -> { if (res == null) return Future.failedFuture(new HttpRequestBindingException("找不到对应的异常处理程序,无法处理当前异常信息: ", cause)); return Future.succeededFuture(res); }); } else { resFuture = Future.failedFuture(new HttpRequestBindingException("未设置异常处理程序,无法处理当前异常信息: ", cause)); } resFuture.onComplete(ar -> { if (ar.failed()) { exceptionThatCannotBeResolved(response, ar.cause()); } else { processResult(request, response, ar.result()); } }); } /** * 处理结果 * * @see VertxInvokeHandler#resultHandle(Object, HttpResponse) */ void processResult(HttpRequest request, HttpResponse response, Object result) { if (!response.ended()) { Future resultFuture; if (!(result instanceof Buffer)) { resultFuture = this.invokeHandler.resultHandle(result, response); } else { resultFuture = Future.succeededFuture((Buffer) result); } resultFuture.onComplete(res -> { if (res.succeeded()) { Buffer resResult = res.result(); if (resResult == null) resResult = EMPTY; response.end(resResult); if (logger.isDebugEnabled()) { RoutingContext routingContext = request.context(); long receiveRequestTime = routingContext.get(RoutingContext.RECEIVE_REQUEST_TIME, System::currentTimeMillis); long handleTime = System.currentTimeMillis() - receiveRequestTime; logger.debug(routingContext.normalisedPath() + " 请求处理完成,耗时:" + handleTime + "ms,响应结果: " + LogFormatUtils.formatValue(resResult, false)); } } else { exceptionThatCannotBeResolved(response, res.cause()); } }); } else { if (logger.isWarnEnabled() && result != null) { logger.warn("响应已经被关闭,丢弃结果: [" + LogFormatUtils.formatValue(result, true) + "]"); } } } /** * 无法解决的异常 */ protected void exceptionThatCannotBeResolved(HttpResponse response, Throwable cause) { HttpResponseStatus responseStatus = HttpResponseStatus.INTERNAL_SERVER_ERROR; response.setStatusCode(responseStatus.code()); response.setStatusMessage(responseStatus.reasonPhrase()); if (logger.isErrorEnabled()) { logger.error("", cause); } response.end(); } /** * 执行匹配上的拦截器的 preHandle 方法 */ Future applyPreHandle(HttpRequest request, HttpResponse response, AtomicInteger interceptorIndex) { if (!ObjectUtils.isEmpty(this.interceptors)) { // 按序执行拦截器 preHandle return FutureUtils.sequential(this.interceptors, (interceptor, termination) -> interceptor.preHandle(request, response, this.invokeHandler).onSuccess(b -> termination.set(!b)), interceptorIndex, true); } return Future.succeededFuture(true); } /** * 在当前响应完全写入网络时调用 */ void triggerAfterCompletion(HttpRequest request, HttpResponse response, AtomicInteger interceptorIndex, @Nullable Throwable cause) { if (!ObjectUtils.isEmpty(this.interceptors) && interceptorIndex.get() != 0) { // 减少1,因为自增从0开始,否者将导致执行未执行的拦截器 interceptorIndex.decrementAndGet(); // 逆序执行拦截器 afterCompletion Future interceptorFuture = FutureUtils.sequential(this.interceptors, (interceptor, termination) -> interceptor.afterCompletion(request, response, this.invokeHandler, cause), interceptorIndex, false); interceptorFuture.onFailure(ex -> logger.error("HandlerInterceptor.afterCompletion 抛出例外!", ex)); } } protected RoutingContext createVertXRoutingContext(io.vertx.ext.web.RoutingContext ctx) { return RoutingContextUtils.createVertXRoutingContext(ctx); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy