2

index.html如今,如果请求的路由与现有 API 端点或其他静态资产不匹配,则需要从后端返回文件(例如 )的情况并不少见。这在使用react-routerand时特别方便browserHistory

我对如何与仆人一起处理这件事有点难过。我确实想知道拦截 404 是否是可行的方法,但是当然有时 API 需要合法地发出 404。这是我一直用来试验的那种东西:

data Wombat = Wombat
  { id :: Int
  , name :: String
  } deriving (Eq, Show, Generic)
instance ToJSON Wombat

wombatStore :: [Wombat]
wombatStore = 
  [ Wombat 0 "Gertrude"
  , Wombat 1 "Horace"
  , Wombat 2 "Maisie"
  , Wombat 3 "Julius"
  ]

wombats :: Handler [Wombat]
wombats = return wombatStore

wombat :: Int -> Handler Wombat
wombat wid = do
  case find (\w -> Main.id w == wid) wombatStore of
    Just x -> return x
    Nothing -> throwE err404

type API = 
    "api" :> "wombats" :> Get '[JSON] [Wombat] :<|>
    "api" :> "wombats" :> Capture "id" Int :> Get '[JSON] Wombat :<|>
    Raw

api :: Proxy API
api = Proxy

server :: Server API 
server = wombats
  :<|> wombat
  :<|> serveDirectory "static"

app :: Application
app = serve api server

main :: IO ()
main = run 3000 app

如果请求与 API 端点或静态目录中的任何内容不匹配,我很想看到一个示例,说明如何添加发送 HTML 响应的“默认路由”。玩具回购在这里

4

2 回答 2

3

你明白了,基本上。serveDirectory "static"可以用任何 wai 替换Application,例如,我们可以有:

...
{-# LANGUAGE OverloadedStrings #-}
...
import Network.Wai        (responseLBS)
import Network.HTTP.Types (status200)
...
server :: Server API 
server = wombats
    :<|> wombat
    :<|> hello

hello :: Application
hello req respond = respond $ 
  responseLBS 
  status200                        -- 
  [("Content-Type", "text/plain")] -- headers
  "Hello, World!"                  -- content
...

粗略地说,wai 应用程序很简单Request -> Response,但文档讲述了一个更完整的故事:

Request -> (Response -> IO ResponseReceived) -> IO ResponseReceived

因此,由于您可以访问 IO,因此您可以检查文件是否存在,如果存在则提供它,否则做任何您喜欢的事情。事实上, wai 定义了type Middleware = Application -> Application,因此您可能会想出一个方便的中间件,将hello(或任何其他应用程序!)包装在文件存在检查器和服务器中。

于 2016-11-17T18:57:03.973 回答
2

这是另一条路线:

serveDirectory定义为

serveDirectory = staticApp . defaultFileServerSettings . addTrailingPathSeparator

defaultFileServerSettings包含一个字段ssLookupFile,如果找不到文件,您可以更改该字段以提供您想要的内容。也许:

import WaiAppStatic.Types
import WaiAppStatic.Storage.Filesystem
import Network.Wai.Application.Static
import System.FilePath

fileOrIndex root pieces = do
  res <- ssLookupFile (defaultFileServerSettings root) pieces
  case res of
    LRNotFound -> undefined -- index.html here
    _ -> return res

serveStatic root =
  let root' = addTrailingPathSeparator root in
  staticApp $ (defaultFileServerSettings root') {ssLookupFile = fileOrIndex root'}
于 2016-11-18T13:25:57.183 回答