2016-11-17 2 views
2

В эти дни нередко требуется вернуть файл (скажем, index.html) из бэкэнд, если запрошенный маршрут не соответствует существующей конечной точке API или другому статическому ресурсу. Это особенно удобно при использовании react-router и 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 

Я бы любите видеть пример того, как я могу добавить добавление маршрута по умолчанию, который отправляет ответ HTML, если запрос не соответствует конечной точке API или чему-либо в статическом каталоге. Toy repo 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

Еще один хороший вариант! Спасибо, что объяснили это. –

Смежные вопросы