我正在查询远程API并遇到了一个问题,当我不希望它发生异常时会抛出异常。我已经检查了类型,似乎没有问题将我需要的值绑定到变量上。
我将Network.HTTP.Client
别名HTTPClient
,import qualified Data.ByteString.Lazy as LBS
别名LBS
。
这是我的GHCi会话的样子:
λ> manager <- HTTPClient.newManager HTTPClient.defaultManagerSettings
λ> request <- HTTPClient.parseUrl postsURL
λ> :t HTTPClient.httpLbs request manager
HTTPClient.httpLbs request manager
:: IO (HTTPClient.Response LBS.ByteString)
λ> response <- HTTPClient.httpLbs request manager
*** Exception: StatusCodeException (Status {statusCode = 403, statusMessage = "Forbidden"}) [("Date","Thu, 21 Aug 2014 20:25:15 GMT"),("Server","Apache/2.2.22 (Ubuntu)"),("Vary","Accept-Encoding"),("Content-Encoding","gzip"),("Content-Length","239"),("Content-Type","text/html; charset=iso-8859-1"),("X-Response-Body-Start","<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n<title>403 Forbidden</title>\n</head><body>\n<h1>Forbidden</h1>\n<p>You don't have permission to access /posts/all\non this server.</p>\n<hr>\n<address>Apache/2.2.22 (Ubuntu) Server at api.pinboard.in Port 80</address>\n</body></html>\n"),("X-Request-URL","GET http://api.pinboard.in:80/posts/all?format=json&auth_token=username:XXXXX")] (CJ {expose = []})
然后,当然:
λ> response
<interactive>:14:1: Not in scope: `response'
我会认为我可以将httpLbs
的结果绑定到响应中,因为它包含在IO monad中,但似乎某种方式引发的异常会阻止这种情况发生。我认为类型应该可以防止这样的情况,但也许我做错了。任何帮助将不胜感激。
答案 0 :(得分:4)
作为您的起点,让我为您举一个实例:
import Network.HTTP.Conduit
import qualified Control.Exception as E
import Network.HTTP.Types.Status
import Data.ByteString.Lazy.Char8 (pack)
main :: IO ()
main = do
let url = "http://www.google.com/does-not-exist.txt"
res <- (simpleHttp url) `E.catch`
(\(StatusCodeException s _ _) -> (return . pack . show . statusCode $ s))
print res
在ghci:
λ> main
"404"
在上面的示例中,我从异常中恢复状态代码404
。您可以按照相同的方法为Exception执行自定义逻辑处理。
更新:使用httpLbs
的方法:
根据forum的建议,您可以将Maybe
包裹在Response
之上并执行异常处理:
import Network.HTTP.Client
import qualified Control.Exception as E
import Network.HTTP.Types.Status (statusCode)
main = do
manager <- newManager defaultManagerSettings
request <- parseUrl "http://www.google.com/does-not-exist.txt"
resp <- (fmap Just $ httpLbs request manager) `E.catch` handleMyException
print resp
handleMyException :: HttpException -> IO (Maybe a)
handleMyException (StatusCodeException s _ _) = if statusCode s == 404
then putStrLn ((show . statusCode $ s) ++ " I'm sorry!") >> return Nothing
else return Nothing
示例演示:
λ> main
404 I'm sorry!
Nothing
我认为类型应该可以防止这样的情况, 但也许我做错了什么。
与现实世界交流时,类型无法保护您。执行IO活动(如读取文件,连接到套接字等)取决于许多外部因素,这些因素不受Haskell(或任何PL)的控制。因此,当这样的事情失败时,Haskell无能为力。但好处是,Haskell明确指出那些IO
动作表明你已经脱离了纯粹的领域。