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

Play Framework 2.8如何实现请求前后拦截 替代Spring HandlerInterceptor功能

Play Framework 2.8 请求拦截(NDC上下文注入)实现方案

Play 框架中没有直接命名为HandlerInterceptor的组件,你的需求可以通过全局ActionCreator(Java推荐) 或 全局Filter(Scala推荐) 实现,逻辑完全对齐Spring的preHandle/postHandle能力,无需使用底层的HttpRequestHandler。

Java版本实现(适配Spring技术栈使用习惯)

1. 自定义全局ActionCreator

实现play.mvc.ActionCreator接口,在请求执行前后插入你的业务逻辑:

import play.mvc.Action;
import play.mvc.Http;
import play.mvc.Result;
import play.mvc.ActionCreator;
import org.slf4j.MDC;
// 如果使用Log4j的ThreadContext,替换为 import org.apache.logging.log4j.ThreadContext;
import java.lang.reflect.Method;
import java.util.UUID;
import java.util.concurrent.CompletionStage;

public class NdcInjectActionCreator implements ActionCreator {
    private static final String NDC_SESSION_KEY = "request_ndc";

    @Override
    public Action createAction(Http.Request request, Method actionMethod) {
        return new Action.Simple() {
            @Override
            public CompletionStage<Result> call(Http.Request req) {
                // preHandle逻辑:读取/生成NDC存入线程上下文
                String ndc = req.session()
                        .get(NDC_SESSION_KEY)
                        .orElseGet(() -> UUID.randomUUID().toString().replace("-", ""));
                MDC.put(NDC_SESSION_KEY, ndc);
                // Log4j版本对应:ThreadContext.put(NDC_SESSION_KEY, ndc);

                // 新生成的NDC回存到session
                Http.Request reqWithNdc = req.addAttr(
                        Http.Attrs.SESSION,
                        req.session().adding(NDC_SESSION_KEY, ndc)
                );

                try {
                    // 执行原请求逻辑
                    return delegate.call(reqWithNdc);
                } finally {
                    // postHandle逻辑:清理线程上下文,避免内存泄漏
                    MDC.remove(NDC_SESSION_KEY);
                    // Log4j版本对应:ThreadContext.remove(NDC_SESSION_KEY);
                }
            }
        };
    }
}

2. 注册组件

在conf/application.conf中添加配置,让Play加载你的自定义ActionCreator:

play.http.actionCreator = "替换为你自己的包名.NdcInjectActionCreator"

Scala版本实现

1. 自定义全局Filter

import akka.stream.Materializer
import play.api.mvc._
import org.slf4j.MDC
import java.util.UUID
import scala.concurrent.ExecutionContext
import scala.util.Try

class NdcInjectFilter(implicit val mat: Materializer, ec: ExecutionContext) extends Filter {
  private val NDC_SESSION_KEY = "request_ndc"

  override def apply(nextFilter: RequestHeader => Future[Result])(request: RequestHeader): Future[Result] = {
    // preHandle逻辑
    val ndc = request.session.get(NDC_SESSION_KEY).getOrElse(UUID.randomUUID().toString.replace("-", ""))
    MDC.put(NDC_SESSION_KEY, ndc)
    val reqWithNdc = request.addAttr(Attrs.Session, request.session + (NDC_SESSION_KEY -> ndc))

    val resultF = nextFilter(reqWithNdc)
    // postHandle逻辑,无论请求成功失败都清理上下文
    resultF.onComplete(_ => Try(MDC.remove(NDC_SESSION_KEY)))
    resultF
  }
}

2. 注册组件

在conf/application.conf中添加配置启用Filter:

play.filters.enabled += "替换为你自己的包名.NdcInjectFilter"

注意事项

  • 如果你在请求中使用了自定义异步线程池,需要自行传递ThreadContext/MDC到子线程,避免上下文丢失
  • 上述实现已经覆盖了异常场景的上下文清理,不会出现内存泄漏问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 12:42:03