2016-11-17 136 views
2

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

我有点难以理解,我可能会如何与仆人接触。我确实不知道是否拦截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响应。玩具回购here

回答

2

你明白了,基本上。 serveDirectory "static"可以通过任何围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 
... 

对于第一近似,围应用只是Request -> Response,但the docs讲一个更完整的故事:

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

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

+0

非常感谢,这真的很有帮助! –

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'} 
+0

另一个不错的选择!谢谢你解释这个。 –