2015-08-24 3 views
12

Я пытаюсь из Content-типа Акка-клиента и, надеюсь, кто-то может пролить свет на следующие вопросы:Акка-клиента: Принять и обработка

  1. Как создать различные маршруты, основанные на акцепт : заголовок в запросе? Например, я хочу, чтобы один кодовый путь обрабатывал «json» и один обрабатывал запросы «xml» (по умолчанию «json», если отсутствует заголовок)

  2. В тех случаях, когда я не хочу, чтобы contentType был Как это определить? Например, в приведенном ниже коде я пытаюсь запустить json через compactPrint(), но это меняет его на строку, следовательно, «text/plain». Я хочу переопределить это и сказать клиенту, что это все еще json.

Мой код - это примерно так;

... 
path("api") { 
      get { 
       complete { 
       getStuff.map[ToResponseMarshallable] { 
        case Right(r) if r.isEmpty => List[String]().toJson.compactPrint 
        case Right(r) => r.toJson.compactPrint 
        case Left(e) => BadRequest -> e 
       } 
       } 
      } 
     } 
... 

Ответ в этом случае является текстовым/открытым, поскольку compactPrint создает строку. критика очень приветствуется. ;)

+1

Чтобы использовать функцию согласования контента в режиме akka-http, вам необходимо предоставить маршаллер для вашего типа источника, который может объединять несколько типов контента. Вы можете использовать 'Marshaller.oneOf' для создания разных маршаллов, где каждый маршаллер знает, как маршалировать только один тип контента. Вы видели документацию о маршаллере по адресу http://doc.akka.io/docs/akka-stream-and-http-experimental/1.0/scala/http/common/marshalling.html#Custom_Marshallers? – jrudolph

+0

Спасибо. Я в конечном итоге пошел по этому маршруту. –

ответ

8

Вы можете определить типа контента следующим образом,

complete { 
      HttpResponse(entity = HttpEntity(ContentType(MediaTypes.`application/json`), """{"id":"1"}""")) 
     } 

Вы можете создать свою собственную директиву как,

def handleReq(json: String) = { 
    (get & extract(_.request.acceptedMediaRanges)) { 
     r => 
     val encoding: MediaRange = 
      r.intersect(myEncodings).headOption 
      .getOrElse(MediaTypes.`application/json`) 
     complete { 
      // check conditions here 
     // HttpResponse(entity = HttpEntity(encoding.specimen, json)) // 
     } 
    } 
    } 

и использовать директиву в маршруте, как

val route = path("api"){ handleReq(json) } 
+0

Спасибо. Я просто надеялся на директиву, чтобы сделать отклонение на основе заголовка, а не охватывать фактическую обработку. Но в любом случае, я закончил реализацию маршаллеров, которые автоматически заботятся о сериализации в XML или JSON, поэтому мне больше не нужен этот подход. Но спасибо за вашу помощь, это помогло мне преодолеть мое разочарование, и это один из способов реализации вещей. Поэтому я приму ответ. –

+0

здесь лучше использовать ContentTypes.'application/json' вместо ContentType (MediaTypes.'application/json') – RomKazanova

1

Потенциальный ответ на вопрос №1, похоже, таков, но я хотел бы сделать это с помощью специальной директивы или чего-то более элегантного. К сожалению, документация для пользовательских директив Akka-Http, похоже, отсутствует.

// the encodings I want, in the order of preference 
val myEncodings = Seq(MediaRange(`application/xml`),MediaRange(`application/json`)) 

    ... 
    path("api") { 
       (get & extract(_.request.acceptedMediaRanges)){ 
        r => 
        val encoding = 
         r.intersect(myEncodings).headOption 
         .getOrElse(MediaRange(`application/json`)) 
        complete { 
         // check "encoding" here and make decision. 
        } 
       } 
      } 
    ... 

Надеясь, что кто-то может обеспечить что-то более чистым.

+0

Я обновил ответ, вы могли проверить, это то, что вам нужно. –

0

Кажется, что принятый ответ больше не работает с akka-http v10.0.3.

Это работает, хотя:

// the encodings I want, in the order of preference 
val myEncodings = Seq(MediaRange(`application/xml`),MediaRange(`application/json`)) 

... 
path("api") { 
      (get & extract(_.request.headers)){ requestHeaders => 
       val mediaTypeNegotiator = new MediaTypeNegotiator(requestHeaders) 
       val encoding = mediaTypeNegotiator 
        .acceptedMediaRanges 
        .intersect(myEncodings) 
        .headOption 
        .getOrElse(MediaRange(`application/json`)) 
       complete { 
        // check "encoding" here and make decision. 
       } 
      } 
     } 
... 

вы также можете сделать

val myEncodings = Seq(MediaRange(`application/xml`),MediaRange(`application/json`)) 

path("api") { 
     (get & extract(_.request.headers)){ requestHeaders => 
     complete { 
      val mediaTypeNegotiator = new MediaTypeNegotiator(requestHeaders) 
      if(mediaTypeNegotiator.accept(MediaTypes.`application/xml`)) { 
      // respond with xml 
      } else if(mediaTypeNegotiator.accept(MediaTypes.`application/json`)) { 
      // respond with json 
      } else { 
      // respond with json by default or reject properly : 
      reject(UnsupportedRequestContentTypeRejection(Set(MediaTypes.`application/xml`, MediaTypes.`application/json`))) 
      } 
     } 
    } 
} 

Hopes это помогает.

Смежные вопросы