2017-01-05 16 views
2

TLS 연결을 사용하여 응답 본문을 얻으려면 http-client 자습서를 사용하고 있습니다. withResponse에 의해 print이 호출됨을 알 수 있기 때문에, 왜 print은 다음과 같은 결과물에 전체 응답을 보내지 않습니까?왜 전체 지연 IO 값을 강제로 인쇄하지 않습니까?

withResponse request manager $ \response -> do 
    putStrLn $ "The status code was: " ++ 
    body <- (responseBody response) 
    print body 

내가 대신 쓸 필요 : 나는 인쇄 할

response <- httpLbs request manager 

putStrLn $ "The status code was: " ++ 
      show (statusCode $ responseStatus response) 
print $ responseBody response 

몸 게으른 ByteString이다. 나는 여전히 print이 전체 값을 인쇄 할 것으로 기대해야하는지 확신 할 수 없다.

instance Show ByteString where 
    showsPrec p ps r = showsPrec p (unpackChars ps) r 
+1

인쇄물은 단지'putStrLn'과'show'입니다. 그래서 당신이 무엇을 묻고 있어야하는지는 "왜 '쇼'가 그 가치를 완전히 평가하지 않는가?"입니다. 일단 신체 유형이 무엇이든간에 Show 인스턴스를 살펴 본다면 대답은 명백 할 것이라고 생각합니다. 강제되는 응답의 유일한 부분은 상태 또는 다른 필드가 아니라 본문이라는 점도 알아 두십시오. –

+0

질문을 다시 읽으면 다른 값인'body'에서 print를 호출 할 때 하나의 값인'response'가 평가되기를 원합니다. 그럴까요? 그렇다면 왜 그 행동을 처음부터 기대할 것입니까? –

+1

첫번째 발췌 문장에서'show (statusCode) ...'줄에 무슨 일이 일어 났습니까? – immibis

답변

3

이 게으름으로 할 필요는 없지만 차이로 Response L.ByteString 당신이 간단한 모듈을 얻을하고는 Response BodyReader 당신은 TLS 모듈을 얻을.

BodyReaderIO ByteString입니다. 그러나 특히 이것은 반복 될 수있는 동작이며, 매번 바이트 청크를 사용합니다. 그것은 그것이 파일의 끝에있을 때를 제외하고 널 바이트 테스트를 보내지 않는 프로토콜을 따른다. (BodyReaderChunkGetter이라고 할 수 있습니다). 아래의 bip은 여러분이 작성한 것과 같습니다 : Response에서 BodyReader/IO ByteString을 추출한 후 첫 번째 청크를 얻기 위해 수행하여 인쇄합니다. 그러나 더 많은 것을 얻기 위해 행동을 반복하지 않습니다. 그래서이 경우 우리는 단지 창세기의 몇 장을 보게됩니다. 당신이 필요로하는 것은 아래의 bop과 같이 덩어리를 배출하는 루프입니다. 이로 인해 킹 제임스 성경 전체가 콘솔에 쏟아집니다.

{-# LANGUAGE OverloadedStrings #-} 
import Network.HTTP.Client 
import Network.HTTP.Client.TLS 
import qualified Data.ByteString.Char8 as B 

main = bip 
-- main = bop 

bip = do 
    manager <- newManager tlsManagerSettings 
    request <- parseRequest "https://raw.githubusercontent.com/michaelt/kjv/master/kjv.txt" 
    withResponse request manager $ \response -> do 
     putStrLn "The status code was: " 
     print (responseStatus response) 
     chunk <- responseBody response 
     B.putStrLn chunk 

bop = do 
    manager <- newManager tlsManagerSettings 
    request <- parseRequest "https://raw.githubusercontent.com/michaelt/kjv/master/kjv.txt" 
    withResponse request manager $ \response -> do 
     putStrLn "The status code was: " 
     print (responseStatus response) 
     let loop = do 
      chunk <- responseBody response 
      if B.null chunk 
       then return() 
       else B.putStr chunk >> loop 
     loop 

루프는 그것이 계시록의 끝까지 출력 단자에 있으므로, EOF 나타내는 빈 문자열을, 때까지 더 덩어리를 얻을 수 돌아가는 유지합니다.

이것은 동작은 간단하지만 약간 기술적입니다. 직접 작성한 재귀를 사용하여 BodyReader으로 만 작업 할 수 있습니다. 그러나 http-client 라이브러리의 목적은 http-conduit과 같은 것을 가능하게하는 것입니다. 그 결과 withResponse의 유형은 Response (ConduitM i ByteString m())입니다. ConduitM i ByteString m()은 도관 유형의 바이트 스트림입니다. 이 바이트 스트림에는 전체 파일이 포함됩니다.

http-client/http-conduit 재료의 원래 형태 인 Response에는 이와 같은 도관이 포함되어 있습니다. BodyReader 부분은 나중에 http-client에 포함되어 있으므로 pipes과 같은 다른 스트리밍 라이브러리에서 사용할 수 있습니다.

그래서 withHTTP 당신에게 유형 Response (ByteString IO())의 응답을 제공의 streamingstreaming-bytestring 라이브러리에 해당하는 HTTP 소재에, 간단한 예제를 촬영합니다. ByteString IO()은 이름에서 알 수 있듯이 IO에서 발생하는 바이트 스트림의 유형입니다. ByteString Identity()은 lazy bytestring (실질적으로 순수 청크 목록)과 동일합니다.이 경우 ByteString IO()은 전체 bytestream을 Apocalypse까지 나타냅니다.당신은 "이 IO`에서 바이트를 추출하지 않기 때문에이 약간 간단 실제로

bap = do 
    manager <- newManager tlsManagerSettings 
    request <- parseRequest "https://raw.githubusercontent.com/michaelt/kjv/master/kjv.txt" 
    Bytes.withHTTP request manager $ \response -> do 
     putStrLn "The status code was: " 
     print (responseStatus response) 
     Bytes.putStrLn $ responseBody response 

: 수입과 그래서

import qualified Data.ByteString.Streaming.HTTP as Bytes -- streaming-utils 
import qualified Data.ByteString.Streaming.Char8 as Bytes -- streaming-bytestring 

프로그램은 게으른 bytestring 프로그램과 동일

 lazy_bytes <- responseStatus response 
     Lazy.putStrLn lazy_bytes 

그러나 다만 쓰기

 Bytes.putStrLn $ responseBody response 

당신은 그 (것)들을 직접 "인쇄"합니다. 당신은 KJV의 중간에서 조금을 보려는 경우, 대신 당신이 게으른 bytestring 때와 수행과 함께 종료 할 수 있습니다

 Bytes.putStrLn $ Bytes.take 1000 $ Bytes.drop 50000 $ responseBody response 

그럼 당신은 아브라함에 대해 뭔가를 볼 수 있습니다.

streaming-bytestringwithHTTP은 우리가 직접 http-client에서 BodyReader 재료를 사용하는 데 필요한 재귀 루프를 숨 깁니다. 예를 들면 동일합니다. withHTTPpipes-http이며, 바이트 청크의 스트림은 Producer ByteString IO()이고, 숫자는 http-conduit입니다. 이 모든 경우에 일단 바이트 스트림을 사용하면 필기 재귀없이 스트리밍 IO 프레임 워크의 일반적인 방식으로 처리 할 수 ​​있습니다. 이들 모두는 http-clientBodyReader을 사용하여이를 수행했으며 이것이 라이브러리의 주요 용도였습니다.