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

Haskell Servant中如何可选捕获路径段?

为Servant应用添加向后兼容的国际化路径支持

我需要以向后兼容的方式为Servant应用添加国际化支持,要求将语言代码设为可选路径段:

  • 若首个路径段属于已知语言代码列表,则使用该语言,处理器接收Just 语言代码
  • 否则默认传入Nothing,服务端将其解析为默认语言

示例:

/some/path => myHandler Nothing
/en/some/path => myHandler (Just "en")
/fr/some/path => myHandler (Just "fr")

为避免编写重复代码(无需为每个端点实现带语言段和不带语言段的两种版本,处理器也无需对应两种变体),我尝试编写一个Servant组合子,检查请求的head $ pathInfo req,若为语言代码则捕获,否则传递Nothing给子服务。但当前实现始终要求pathSegment必须存在,无法实现可选捕获,代码如下:

data HostWithLocale = HostWithLocale

instance (HasServer api context) => HasServer (HostWithLocale :> api) context where
  type ServerT (HostWithLocale :> api) m = (Hostname, Maybe LanguageCode) -> ServerT api m
  
  hoistServerWithContext _ pc nt s = hoistServerWithContext (Proxy :: Proxy api) pc nt . s  

  route _ context server = 
    CaptureRouter [hint] $ route (Proxy :: Proxy api) context subserver
    where
      hint = CaptureHint "language" (typeRep (Proxy :: Proxy (Hostname, Maybe LanguageCode)))
      subserver = addCapture server $ \pathSegment -> withRequest $ \req -> 
        case DL.lookup (fromString "Host") (requestHeaders req) of
          Nothing -> 
            delayedFail err406
          Just hname -> 
            if Prelude.not (isWhiteListedDomain hname)
              then delayedFail err406
              else if pathSegment `DL.elem` knownLanguageCodes
                then pure $ (toS hname, Just $ LanguageCode pathSegment)
                else pure $ (toS hname, Nothing)

isWhiteListedDomain :: C8.ByteString -> Bool
isWhiteListedDomain = undefined 
    
knownLanguageCodes :: [Text]
knownLanguageCodes = undefined

内容的提问来源于stack exchange,提问作者Saurabh Nanda

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 20:22:34