在httpclient中获取RequestBody

get RequestBody in httpclient

我想使用 Haskell 直接使用 bloodhound 或 REST api 向亚马逊托管的弹性搜索服务器发送请求。

由于服务器有基于 IAM 的访问策略,我需要签署 signature。为了对每个请求进行签名,需要计算有效负载的哈希值。我不确定如何将 RequestBody(分块或不分块)放入 ByteString。

对于您的特定用例:在我看来 wreq 库已经支持 AWS IAM 签名 (tutorial),因此根据您的特定要求,使用that/look 了解其工作原理。

看起来使用 RequestBodys 最简单的方法实际上可能只是编写一个函数来计算 6 种可能的 RequestBodys 中的每一种的签名,或者至少您需要的那些,而无需尝试重​​新使用 http-client 的机制将 6 个中的任何一个转换为一个 ByteString。这是一个特别有用的选项,因为看起来您可能需要为分块请求做一些特殊的事情。 RequestBody 只有几个选项,而且只有两个(基于流的)似乎很难使用;那些通常也值得特殊对待(特别是因为,根据请求的创建者如何实现它们,我不清楚是否可以保证可以从它们中读取并让它们以后仍然工作)。 source 可能对这种方法有用。

根据您使用 Haskell 的经验,流构造器可能有点令人生畏。然而它实际上还不错:扩展类型同义词给出 GivesPopper () = (IO ByteString -> IO ()) -> IO ()IO ByteString -> IO () 函数是你可以提供的,它接受流块的生产者(每次评估都会产生一个更多的块)并用它做一些有用的事情——例如,将该块写入列表中的 IORef 以便稍后检查。如果您在此函数上调用 GivesPopper,您将获得一个 IO 操作,该操作以有用的生产者作为参数运行它。例如:

foo :: NeedsPopper ()
foo pop = do
  chunk <- pop
  if (chunk == "") then return ()
                   else BS.putStr chunk >> foo pop

将在传递给 GivesPopper () 时将流式响应 body 打印到标准输出。

如果您希望请求可以多次构建而不会出现问题(任何流 GivesPopper 必须可以多次调用,等等),并且您希望重用 http-client 的内部响应渲染,你也许可以摆脱像这样非常 hacky 的东西:

getRequest :: Request -> IO BS.ByteString
getRequest req = do
  (conn, out, inp) <- dummyConnection []
  let req' = req { requestHeaders = (CI.mk "Expect", "100-continue")
                                  : requestHeaders req
                 }
  (Just later) <- requestBuilder req' conn
  _ <- out
  later
  BS.concat <$> out

似乎 http-client 呈现 Response 的唯一地方是在 requestBuilder 中,并且在构建请求时,这将始终发送 headers,我认为这不是你想要的。 _ <- out 行从虚拟连接中清除 header+body,并且,由于给出了 Expect: 100-continue,因此 later 应该写入 body再次虚拟连接。请注意,这仅在可以毫无问题地多次构建响应时才有效。如果您的请求实际上希望将 continue 功能用于不同的东西,这可能不会很好地工作。另请注意,这将写出分块请求的编码版本(例如 "6\r\na body\r\n0\r\n\r\n"),这可能是也可能不是您想要的。