2014-12-23 9 views
6

버퍼/열거를 통해 실행,이 같은 코드를 내가 원하는대로 주석 처리 된 코드는 인쇄 것, 내 말은, 작동하지 않는 :재생/로그/인쇄 응답 바디/내가 플레이 프레임 워크에 응답 본문을 인쇄하는 방법을 찾고 있어요 몸

Response: 
id=1 
[email protected] 

그래서, 내가 열거 [배열 [바이트]]에서 문자열을 얻을 수있는 방법을 찾아야합니다. 나는이 읽어 열거의 개념을 파악하려 : http://mandubian.com/2012/08/27/understanding-play2-iteratees-for-normal-humans/

그래서 ...를, 내가 제대로 이해한다면 :

  1. 내가해야 그것을 변환하는 과정에서 건조하지 업 열거 String에 전달합니다. 그렇지 않으면, 클라이언트는 아무것도 수신하지 못합니다.

  2. T/필터 메커니즘을 구현하는 방법을 알아 냈다고 가정 해 봅시다. 그렇다면 ... non-blocking 스트리밍 프레임 워크로서 Play 프레임 워크의 목적을 무력화시키지 않겠는가? (왜냐하면 나는 toString을 호출하기 전에 메모리에 완전한 바이트 배열을 구축하고 마침내 로깅하기 때문이다)?

그렇다면 응답을 기록하는 올바른 방법은 무엇입니까? 사전에

감사합니다, Raka

+0

스트리밍 방식으로 응답을 기록해야합니다. 예 : 'System.out'은'OutputStream'입니다. 스트리밍 방식으로 로그인 할 수 있습니다 (두 개의 응답이 인터리빙 될 수도 있습니다). 데이터베이스에 로깅하는 경우 해당 데이터베이스로 스트리밍 할 수 있습니다. 등등. – lmm

+0

나는 대답을 찾은 것 같아, 여기 : http://stackoverflow.com/questions/17752151/scala-play-2-1-accessing-request-and-response-bodies-in-a-filter –

답변

3

이 코드는 작동이 : Scala Play 2.1: Accessing request and response bodies in a filter :

object AccessLoggingAction extends ActionBuilder[Request] { 
    def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = { 
    val start = System.currentTimeMillis 

    Logger.info(s"""Request: 
     id=${request.id} 
     method=${request.method} 
     uri=${request.uri} 
     remote-address=${request.remoteAddress} 
     body=${request.body} 
    """) 

    val resultFut = block(request) 

    resultFut.map {result => 
     val time = System.currentTimeMillis - start 
     Result(result.header, result.body &> Enumeratee.map(arrOfBytes => { 
     val body = new String(arrOfBytes.map(_.toChar)) 
     Logger.info(s"""Response: 
     id=${request.id} 
     method=${request.method} 
     uri=${request.uri} 
     delay=${time}ms 
     status=${result.header.status} 
     body=${body}""") 
     arrOfBytes 
     }), result.connection) 
    } 
    } 
} 

나는 부분적으로 여기에서 (열거 밖으로 바이트 배열을하는 방법에 대한)을 배웠습니다.

내가 사용하는 링크가 2.1을 사용하면서 (더 이상 2.3에없는 PlainResult를 계속 사용함) Play 2.3.7을 사용하고 있습니다.

1

본인은 위의 대답을 출발점으로 사용했지만 신체가 존재하는 경우에만 답변을 기록한다는 점에 유의했습니다. 우리는이에 적응했습니다

var responseBody = None:Option[String] 
val captureBody = Enumeratee.map[Array[Byte]](arrOfBytes => { 
    val body = new String(arrOfBytes.map(_.toChar)) 
    responseBody = Some(body) 
    arrOfBytes 
}) 
val withLogging = (result.body &> captureBody).onDoneEnumerating({ 
    logger.debug(.. create message here ..) 
}) 
result.copy(body=withLogging) 
2

이 나에게 나타납니다 때, (https://stackoverflow.com/a/27630208/1781549에서 제안으로) 그 결과 몸이 두 개 이상의 덩어리에 표시됩니다 당신이 result.body &> Enumeratee.map 내부에 로그인 할 경우, 각각의 덩어리가 될 것입니다 독립적으로 기록됩니다. 당신은 아마 이것을 원하지 않을 것입니다. 이 전체 아이디어가 로그인하기 전에 result.body 열거의 모든 데이터를 사용하는 것입니다 (새로운 열거를 반환) :

나는 이런 식으로 구현 것 :

val ret = block(request).flatMap { result => 
    val consume = Iteratee.consume[Array[Byte]]() 
    val bodyF = Iteratee.flatten(result.body(consume)).run 
    bodyF.map { bodyBytes: Array[Byte] => 
    // 
    // Log the body 
    // 

    result.copy(body = Enumerator(bodyBytes)) 
    } 
} 

그러나 경고. 따라서 응답이 크거나 스트리밍에 의존한다면 아마도 원치 않는 것일 수도 있습니다.