如何在WAI中间件中获取响应状态码?
在WAI中间件中获取响应状态码的实现
要获取响应状态码,核心是包装原respond函数——WAI的中间件模型里,prevApp返回的ResponseReceived只是一个响应已发送的标记,真正的Response是通过respond回调传递的。
完整实现代码
import qualified Network.Wai as WAI import Data.IORef import Data.Text (Text) import qualified Data.Text as T myMiddleware :: WAI.Middleware myMiddleware prevApp req respond = do -- 创建IORef存储响应状态码 statusRef <- newIORef Nothing -- 包装原respond函数,拦截Response并提取状态码 let myRespond resp = do let status = WAI.responseStatus resp atomicWriteIORef' statusRef (Just status) -- 执行原respond逻辑发送响应 respond resp -- 调用上游应用,传入包装后的respond _ <- prevApp req myRespond -- 取出状态码做后续处理(比如日志) maybeStatus <- readIORef statusRef case maybeStatus of Just status -> do let path = T.intercalate "/" $ WAI.pathInfo req method = WAI.requestMethod req -- 这里替换成你的业务逻辑,比如记录日志 putStrLn $ "Request " ++ show method ++ " " ++ show path ++ " returned status " ++ show status Nothing -> pure () -- 返回响应已接收的标记 pure WAI.ResponseReceived
你的疑问解答
这是否是最简单、最常用的解决方案?
是的,这是WAI生态里处理这类需求的标准方案。因为WAI的响应是通过回调异步传递的,要在prevApp执行完成后获取响应数据,必须用可变存储(如IORef)来传递状态。如果是单写单读场景,IORef比MVar更轻量,是首选。创建IORef的开销如何?每次请求都创建是否可行?
IORef的创建开销极低,本质就是堆上分配一个极小的内存单元,完全可以每次请求创建一个。Haskell运行时对这类轻量级可变变量的管理效率很高,不会造成性能问题。
简化场景补充
如果你的需求只是在响应发送时执行逻辑(比如实时打日志),甚至不需要IORef——直接在包装的respond里处理状态码即可,不用把状态传递到prevApp之后:
myMiddleware :: WAI.Middleware myMiddleware prevApp req respond = prevApp req $ \resp -> do let status = WAI.responseStatus resp path = T.intercalate "/" $ WAI.pathInfo req method = WAI.requestMethod req putStrLn $ "Request " ++ show method ++ " " ++ show path ++ " returned status " ++ show status respond resp
这种写法更简洁,适合不需要在prevApp完成后再处理状态的场景。
内容的提问来源于stack exchange,提问作者RandomB
相关产品推荐
相关产品推荐

