2015-12-16 8 views
5

Я работаю с устаревшим HTTP API (который я не могу изменить), который отвечает JSON в теле, но дает заголовок Content-Type: text/plain; charset=utf-8.Как развязать `text/plain` как JSON в Akka HTTP

Я пытаюсь маршализацию что HTTP тело как JSON, но я получаю следующее исключение: akka.http.scaladsl.unmarshalling.Unmarshaller$UnsupportedContentTypeException: Unsupported Content-Type, supported: application/json

Мой код выглядит следующим образом:

import spray.json.DefaultJsonProtocol 
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ 
import akka.http.scaladsl.unmarshalling._ 

case class ResponseBody(status: String, error_msg: String) 

object ResponseBodyJsonProtocol extends DefaultJsonProtocol { 
    implicit val responseBodyFormat = jsonFormat2(ResponseBody) 
} 

def parse(entity: HttpEntity): Future[ResponseBody] = { 
    implicit val materializer: Materializer = ActorMaterializer() 
    import ResponseBodyJsonProtocol._ 
    Unmarshal[HttpEntity](entity).to[ResponseBody] 
} 

Ответ пример HTTP выглядит следующим образом:

HTTP/1.1 200 OK 
Cache-Control: private 
Content-Encoding: gzip 
Content-Length: 161 
Content-Type: text/plain; charset=utf-8 
Date: Wed, 16 Dec 2015 18:15:14 GMT 
Server: Microsoft-IIS/7.5 
Vary: Accept-Encoding 
X-AspNet-Version: 4.0.30319 
X-Powered-By: ASP.NET 

{"status":"1","error_msg":"Missing parameter"} 

Что я могу сделать, чтобы игнорировать Content-Type в ответе HTTP и анализировать как JSON?

ответ

6

Один из способов я нашел только вручную установить Content-Type на HttpEntity перед тем демаршаллизации его:

def parse(entity: HttpEntity): Future[ResponseBody] = { 
    implicit val materializer: Materializer = ActorMaterializer() 
    import ResponseBodyJsonProtocol._ 
    Unmarshal[HttpEntity](entity.withContentType(ContentTypes.`application/json`)).to[ResponseBody] 
} 

Кажется, работает нормально, но я открыт для других идей ...

+0

У меня была подобная проблема, и у меня была последняя строка кода для Unmarshalling. По какой-то причине параметр withContentType изменяет сущность и преобразует ее в строгий объект, который также содержит объект типа контента. Любая идея о том, как извлечь тело из этого? –

2

I 'd использовать директиву map.... Он выглядит коротким и элегантным.

val routes = (decodeRequest & encodeResponse) { 
    mapResponseEntity(_.withContentType(ContentTypes.`application/json`)) { 
    nakedRoutes ~ authenticatedRoutes 
    } 
} 
+0

Я не уверен, что это применимо .... в моем случае нет маршрутизации, и я, конечно, не вижу, как это короче или элегантнее моего ответа. Тем не менее, идея. –

+1

О да, если вы не используете Spray DSL, то он не применяется. – expert