2017-01-05 18 views
2

Я использую http-client учебник, чтобы получить тело ответа с использованием TLS-соединения. Поскольку я могу заметить, что print вызывается withResponse, почему не print принудительно весь ответ на результат в следующем фрагменте?Почему не печатает силу всего ленивого значения ввода-вывода?

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 

Body Я хочу напечатать ленивый байтовой строки. Я все еще не уверен, следует ли ожидать print для печати всего значения.

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

Печать - это просто 'putStrLn' и' show'. Так что вы, вероятно, должны спрашивать: «Почему« Show »полностью не оценивает значение?». Я подозреваю, что ответ будет очевиден, если вы посмотрите на экземпляр Show для любого типа тела. Также обратите внимание, что единственной частью ответа, который был бы вынужден, является тело, а не статус или другие поля. –

+0

Повторное чтение вашего вопроса, кажется, вы хотите, чтобы одно значение, 'response', было оценено при вызове печати на другое значение,' body'. Это так? Если да, то почему вы ожидаете такого поведения в первую очередь? –

+1

Что случилось с строкой 'show (statusCode) ...' в первом фрагменте? – immibis

ответ

3

Это не нужно делать с ленью, но с той разницей между Response L.ByteString вы получаете с простым модулем, и Response BodyReader вы получаете с модулем TLS.

Вы заметили, что BodyReader является IO ByteString. Но, в частности, это действие, которое можно повторить, каждый раз с следующий фрагмент байтов. Он следует протоколу, что он никогда не отправляет нулевую байтов, кроме случаев, когда она находится в конце файла. (BodyReader, возможно, был назван ChunkGetter). bip ниже похоже на то, что вы написали: после извлечения BodyReader/IO ByteString из Response он выполняет его, чтобы получить первый кусок и распечатывает его. Но не повторяет действие, чтобы получить больше - так что в этом случае мы просто видим первые главы главы книги Бытия. Вам нужна петля для извлечения кусков, как в 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 

Цикл продолжает идти назад, чтобы получить больше кусков, пока она не получает пустую строку, которая представляет ВФ, поэтому в терминале он печатает до конца Апокалипсиса.

Это поведение простое, но слегка техническое. Вы можете работать только с BodyReader рукописной рекурсией. Но цель библиотеки http-client - сделать такие вещи, как http-conduit. Там результат withResponse имеет тип Response (ConduitM i ByteString m()). ConduitM i ByteString m() - как типы каналов байтового потока; этот поток байтов будет содержать весь файл.

В оригинальной форме изделия http-client/http-conduit материал Response содержит такой трубопровод; часть BodyReader была позже преобразована в http-client, поэтому ее могли использовать различные потоковые библиотеки, такие как pipes.

Так простой пример, в соответствующем HTTP материала для streaming и streaming-bytestring библиотек, withHTTP дает ответ типа Response (ByteString IO()). ByteString IO() - тип потока байтов, возникающего в IO, как следует из его названия; ByteString Identity() будет эквивалентом ленивого байта (фактически, чистого списка кусков). ByteString IO() в этом случае будет представлять весь байтовый поток до Апокалипсиса.Так с импортом

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

программа идентична ленивой программа: байтовой строки

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 

Действительно, это немного проще, так как вы не «извлечь байты из IO`:

 lazy_bytes <- responseStatus response 
     Lazy.putStrLn lazy_bytes 

но просто написать

 Bytes.putStrLn $ responseBody response 

вы просто «печатаете» их напрямую. Если вы хотите просмотреть только немного от середины БКИ, вы можете вместо этого делать то, что вы бы с ленивой байтовой строкой, и заканчиваетесь:

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

Тогда вы увидите что-то об Аврааме.

withHTTP для streaming-bytestring просто скрывает рекурсивную зацикливание, что нам нужно использовать BodyReader материал из http-client непосредственно. Это то же самое, например. с withHTTP вы найдете в pipes-http, который представляет собой поток байтовых строк, как Producer ByteString IO(), и то же самое с http-conduit. Во всех этих случаях, когда у вас есть руки на потоке байтов, вы обрабатываете его способами, типичными для потоковой структуры ввода-вывода без рукописной рекурсии. Все они используют BodyReader от http-client, чтобы сделать это, и это было основной целью библиотеки.

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

  • Нет связанных вопросов^_^