在 servant 中,我如何 select 我的异常基于 Accept header?

In servant, how can I select my exception based on Accept header?

就上下文而言,这是一种身份验证情况。在我的应用程序中,如果客户端未通过身份验证,那么应用程序显然需要做出适当的响应。当我想根据调用服务器的应用程序类型选择不同的响应时,挑战就来了。

这是一个路线示例:

server =    Header "Cookie" (AuthToken Unverified)
         :> "api" :> "history" :> Get '[HTML, JSON] HistoryPage

因此,HTML 响应将用于 CGI 应用程序。通常,它应该呈现一个身份验证页面,或者它应该抛出 303 以将用户定向到身份验证页面。

但是 JSON 响应将用于 Javascript 应用程序,我只想 return 一个 404,因为 Javascript 会有其他方式正在进行身份验证。

这是我的 top-level 处理程序:

newtype WebM a = WebM (ReaderT Context (ExceptT WebExc IO) a)
data WebExc = OtherExceptionTypes
            | AppUnauthorized

runWeb :: Context -> WebM :~> Handler
runWeb ctx@Context{..} = Nat $ \(WebM action) -> withExceptT trExc $ runReaderT action ctx
  where
    trExc :: WebExc -> ServantErr
    trExc AppUnauthorized = err303 { .. }

我尝试创建自己的 Javascript content-type,但 MimeRenderer 不允许我抛出异常。到目前为止我唯一的想法是捕获 "Accept" header 并从处理程序中抛出 303404 。但这很恶心,因为处理程序不应该知道有关实际客户端应用程序的任何信息。

有没有更简洁的方法来处理这个问题?

没有完全回答你的问题,但从更大的角度来看,这听起来像是两个独立路由的用例,它们之间共享一个共同的实现位。