0

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

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

4

1 回答 1

1

对于您的特定用例:在我看来,该wreq库已经支持 AWS IAM 签名(教程),因此根据您的特定要求,使用它/查看它是如何工作的可能是最简单的。

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

根据您使用 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

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

如果您希望可以多次构建请求而不会出现问题(任何 stream 都GivesPopper必须可以多次调用,等等),并且您希望重用http-client的内部响应呈现,那么您可能能够摆脱一些非常骇人听闻的事情,例如这个:

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呈现 a的地方Response是 in requestBuilder,并且在构建请求时,这将始终发送标头,我认为这不是您想要的。该_ <- out行从虚拟连接中清除了 header+body,并且,既然Expect: 100-continue给出了,later那么应该再次将 body 写入虚拟连接。请注意,这只适用于可以多次构建响应而没有问题的情况。如果您的请求实际上希望将该continue功能用于不同的东西,那么这可能效果不佳。另请注意,这将写出分块请求的编码版本(例如"6\r\na body\r\n0\r\n\r\n"),这可能是也可能不是您想要的。

于 2018-07-08T07:19:16.343 回答