Это не нужно делать с ленью, но с той разницей между 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
, чтобы сделать это, и это было основной целью библиотеки.
Печать - это просто 'putStrLn' и' show'. Так что вы, вероятно, должны спрашивать: «Почему« Show »полностью не оценивает значение?». Я подозреваю, что ответ будет очевиден, если вы посмотрите на экземпляр Show для любого типа тела. Также обратите внимание, что единственной частью ответа, который был бы вынужден, является тело, а не статус или другие поля. –
Повторное чтение вашего вопроса, кажется, вы хотите, чтобы одно значение, 'response', было оценено при вызове печати на другое значение,' body'. Это так? Если да, то почему вы ожидаете такого поведения в первую очередь? –
Что случилось с строкой 'show (statusCode) ...' в первом фрагменте? – immibis