喷雾中的拦截器/过滤器

时间:2014-12-18 12:08:34

标签: scala spray

我正在忙着将我们的Spring / Groovy应用程序之一迁移到Spray / Scala。我对Spray很新,所以如果这是一个初学者问题,请原谅我。

目标是模拟我们的日志记录拦截器,它记录每个请求/响应的各种数据。在这部分代码中有很多逻辑,所以它不是一个简单的日志行。另外,我想用这个逻辑包装所有请求。

现有的Groovy / Spring拦截器:

boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler {
  //do some logging logic
}


void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
  //do some more logging logic
}

我的Scala演员看起来像这样

class BootServiceActor extends Actor with ViewingController with LazyLogging with ViewingWire {

def actorRefFactory = context

implicit val ctx = context.dispatcher

def receive = runRoute(route)(exceptionHandler, RejectionHandler.Default, context,
  RoutingSettings.default, LoggingContext.fromActorRefFactory)
}

2 个答案:

答案 0 :(得分:5)

Spray / Scala的一大卖点是你可以避免“魔法”,拦截器等无形的东西。您可以通过使用类型和/或指令来实现相同的功能,但是您所做的一切在代码中都可见,并且由于类型系统,因此可以重构。例如。您可以使用scalaz Writer来累积与特定请求关联的日志消息,然后为具有现有编组的任何Marshaller[Writer[MyLogStructure, A]]定义提供A的“元编组器”,以及以正确的结构编写了该特定请求的所有日志。如果您愿意,我很乐意详细介绍这种方法。

“预处理”部分最好由简单的Directive处理;因为Spray是反应性的和异步的,所以并不存在配对“前后”处理的概念。相反,您对请求执行某些操作并将其交给下一个处理步骤,最终将发送响应。如果你需要将一些“上下文”从预处理传递到后句柄,那么可能最好用“上下文类型”(我试图避免说出可怕的m字),如{{1 }}

答案 1 :(得分:1)

解决方案我是根据lmm的输入实现的

我最终制定了一个自定义指令,其中包含以下内容:

trait LoggingDirectives {

  val logger = LoggerFactory.getLogger(classOf[LoggingDirective])

  import spray.routing.directives.BasicDirectives._

  def logResponseInfo(user : String): Directive0 =
    mapRouteResponse { response ⇒
      //...
      logger.info("RESPONSE >> "+user+":"+response)
      response
    }

  def logRequestInfo: Directive0 =
    mapRequest { request ⇒
      //...
      logger.info("REQUEST << " + request);
      request
    }
}

然后我把它包裹在我的路线上:

val route = logRequestInfo {
  accountAuthenicationValidator { profileId:String =>
    logResponseInfo(profileId) {
      controllerRoute(profileId)
    }
  }
}

其中accountAuthenicationValidator是另一个自定义指令,controllerRoute是处理所有路径的核心路径,是(String =&gt; Route)