2016-11-17 140 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

另一個不錯的選擇!謝謝你解釋這個。 –