2014-07-04 3 views
4

Я пишу пользовательскую директиву в Spray, которая будет управлять ограничением скорости для любого пользовательского запроса.Как получить контекст запроса в пользовательской директиве?

У меня будет LimitManager где-нибудь, где будут обрабатываться пользовательские лимиты и правила для каждого запроса. Единственной информацией, необходимой для этого LimitManager, является userInfo и currentRoute, то есть разные пределы для разных маршрутов.

Так что, вероятно, в конечном итоге, что-то вроде этого для директивы:

def ensureLimit(): Directive0 = 
    if (LimitManager.isAuthorized(userInfo, currentRoute)) { 
    pass 
    } else { 
    reject 
    } 

Как я могу получить контекст запроса внутри директивы, так что я могу обеспечить правильную информацию на мой LimitManager?

ответ

7

В Spray каждая директива является функцией над Route, которая является псевдонимом для функции RequestContext => Unit. Но с помощью могучего Scala подразумевает, маршрутизации DSL помогает скрыть это, но вы можете написать такие вещи, как это:

val route: Route = get { (ctx: RequestContext) => // this can be omitted, just for info 
    ctx.complete("Hello") 
} 

это то же самое, как:

val route: Route = get { complete("Hello") } 

Но с некоторыми сложными трюками синтаксических ,

ПОМНИТЕ! что вы никогда не должны писать так:

val route = get { ctx => 
    complete("Alloha") 
} 

В здесь complete превратилась бы в ctx => ctx.complete("Hello"), так что вы бы вернуть эту функцию на ваш запрос и не завершит реальный запрос.

Итак, один способ, как вы можете это сделать, просто передайте в качестве аргумента. Также вы можете использовать extract директиву, чтобы получить контекст, а затем использовать map или flatMap, чтобы сделать свой собственный:

val myDirective = extract(identity) map { ctx => /* Your directive */ } 
+1

Чтобы добавить к ПОМНИТЕ! раздел с расширением мысли, вы можете столкнуться с ситуацией, когда вам нужна ссылка «RequestContext», а также использовать больше директив (а не просто «завершить»). В этом случае вы можете передать объект 'RequestContext' вручную. Например, если вам нужно обрабатывать фьючерсы: 'get {ctx => onComplete (someFutureProducer (ctx)) {...} (ctx)}' – Rich