如何使用Network.HTTP.receiveHTTP在Haskell中编写简单的HTTP服务器

时间:2011-05-27 20:13:36

标签: http haskell

模块Network.HTTP 公开了我想用于非常基本的Web服务器的函数receiveHTTPrespondHTTP。我写了一个等待客户端的存根:

{-# LANGUAGE OverloadedStrings #-}
module Main where

import Network.HTTP
import Network
import Control.Monad

main = withSocketsDo $ do
  socket <- listenOn $ PortNumber 8080
  forever $ do
    (handle, host, port) <- accept socket
    print (host, port)

此处accpet为我提供Handle,现在我无法弄清楚如何将HandlereceiveHTTP一起使用。

我在Google上找到了an example,但它是从2008年开始的,不再适用了。我无法移植它。

有什么想法吗?

2 个答案:

答案 0 :(得分:6)

你可以这样做,但我真的认为你不应该这样做。 HTTP可以充当服务器,但设计用于客户端。我用Google搜索了一下,我找不到任何实际使用respondHTTP的人的例子。如果您在2016年使用http-conduit进行客户端HTTP。在服务器端,warp或依赖它的东西可能就是你想要的。

然而,这是代码。

#!/usr/bin/env stack
-- stack --resolver lts-6.3 --install-ghc runghc --package HTTP
{-# LANGUAGE RecordWildCards #-}
import Control.Monad
import qualified Data.ByteString as B
import Network.HTTP
import Network.Socket
import Network.URI

main = do
  lsock <- socket AF_INET Stream defaultProtocol
  bind lsock (SockAddrInet 8080 iNADDR_ANY)
  listen lsock 1
  forever $ do
    (csock, _) <- accept lsock
    hs <- socketConnection "" 8080 csock
    req <- receiveHTTP hs
    case req of
      Left _ -> error "Receiving request failed"
      Right (Request {..}) -> if uriPath rqURI == "/"
                            then do
                              respondHTTP hs $
                                Response (2,0,0) "OK" [] "Hello HTTP"
                              Network.HTTP.close hs
                            else do
                              respondHTTP hs $
                                Response (4,0,4) "Not found" [] "Nothing here"
                              Network.HTTP.close hs

以上使用Stack对shebang脚本的支持。 chmod +x它或stack foo.hs运行它。

不推荐使用Network模块。如果需要套接字API,请始终使用Network.Socket。对于更高级别的内容,请使用connection

您执行正常的POSIX套接字操作,然后将连接的套接字转换为HandleStream socketConnection,并在其上运行respondHTTPreceiveHTTPsocketConnection是一个奇怪的功能。前两个参数是主机名和运行服务器时不使用AFAICT的端口。

我使用了RecordWildCards扩展名。它允许我在一个模式中编写Right (Request {..}),并将记录的所有字段放在右侧。

答案 1 :(得分:5)

也许它希望您使用the accept function from Network.Socket代替Network?这会为您提供Socket而不是Handle,您应该可以将其转换为receiveHTTP可以使用的表单。

通常情况下,Handle可以更好地直接使用,但是这里HTTP库正在为您处理它,所以它需要更低级别的接口。

编辑:在进一步查看后,似乎socketConnection中的Network.TCP功能可以满足您的需求。有趣的是,它实际上是在内部插入Handle之前将其从内部读取,但似乎没有提供从外部提供的Handle读取的方法。该函数的字符串参数应该是远程主机的名称,但它看起来只是保留供参考;它实际上并没有启动与该主机或任何东西的连接。