如何在Haskell Servant中解析无Content-Type头的API响应?
解决Servant解析无Content-Type的纯文本响应问题
当第三方API未指定Content-Type头仅返回纯文本时,Servant默认的解析逻辑会因为无法匹配对应MIME类型而报错,以下是两种常用的解决思路:
方法一:自定义通用MIME类型解析为Text
通过定义一个匹配任意Content-Type的类型,并实现对应的解析实例,让Servant直接将响应体转为Text:
- 定义通用Accept类型
data AnyContent instance Accept AnyContent where contentType _ = "*/*" -- 匹配所有Content-Type
- 实现Text的MimeUnrender实例
import Data.Text.Encoding (decodeUtf8) import Servant.API (MimeUnrender(..)) instance MimeUnrender AnyContent Text where mimeUnrender _ body = Right $ decodeUtf8 body
- 在API类型中使用
type ThirdPartyAPI = "target-endpoint" :> Get '[AnyContent] Text
之后通过Servant客户端调用就能直接拿到Text类型的响应内容。
方法二:获取原始响应手动转换(更灵活)
如果需要额外处理响应头或做更复杂的错误处理,可以直接获取原始响应体再手动转换:
- 定义返回原始响应的API
import Network.HTTP.Client (Response) import Data.ByteString (ByteString) type ThirdPartyAPI = "target-endpoint" :> Get '[()] (Response ByteString)
- 手动转换为Text(含错误处理)
import Data.Text.Encoding (decodeUtf8') import Servant.Client (ClientM, client, throwError, ServantError) import Control.Monad.Except (ExceptT(..)) getRawResponse :: ClientM (Response ByteString) getRawResponse = client ThirdPartyAPI getResponseText :: ClientM Text getResponseText = do resp <- getRawResponse case decodeUtf8' $ responseBody resp of Right txt -> return txt Left err -> throwError $ ServantError $ "Failed to decode text: " ++ show err
转换为自定义类型
如果需要将响应转为自定义类型,只需扩展MimeUnrender实例即可:
data MyCustomType = MyCustomType Text deriving (Show, Eq) instance MimeUnrender AnyContent MyCustomType where mimeUnrender _ body = Right . MyCustomType $ decodeUtf8 body
之后API类型改为Get '[AnyContent] MyCustomType,客户端调用就能直接得到自定义类型的结果。
内容的提问来源于stack exchange,提问作者DarkHorse1997
相关产品推荐
相关产品推荐

