You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 16:31:04