2016-02-25 70 views
6

我試圖將一些ByteString中繼給客戶端(瀏覽器)。客戶端將不知道被請求文檔的內容類型,因此我試圖將適當的內容類型響應發送回客戶端。該文檔可以是圖像或pdf或word文檔等。在僕人中發送通用內容類型

例如,客戶端將請求/document?id=55,服務器將響應相應的內容類型和關聯的ByteString

我遵循示例here:我爲圖像創建了一些東西。

data IMAGE 

instance Accept IMAGE where 
    contentType _ = "image" M.// "jpeg" 

instance MimeRender IMAGE LBS.ByteString where 
    mimeRender _ = id 

面臨的挑戰是客戶端將無法與某些特定Accept:頭髮送請求,所以沒有辦法像它完成here我用適當的Mime類型反應。此外,以上僅適用於圖像(假設瀏覽器將推斷出png,即使我發送回jpeg),但不適用於pdf,docx等。

我想過一個paramaterized型像MyDynamicContent String,我會在運行時的內容類型通過,但我不知道我怎麼會宣佈我的API,即我將要使用的,而不是'[JSON]。因爲這些例子只是一個簡單的數據類型,所以不確定這種事情是否可能。

所以我的問題是,如果我想送一些ByteString作爲響應和動態設置Content-Type頭,會是怎樣做到這一點的最好方式使用servant

更新:我已經打開了一個issue

+0

服務器如何決定使用哪種內容類型進行響應? (特別是,爲了確認,這不能被靜態確定?) – user2141650

+0

@ user2141650:'server'從數據存儲(文檔存儲服務)獲取此信息。它調用服務,服務響應內容類型和字節字符串。我知道我可以爲每種內容類型(或者至少大部分使用的內容類型)創建一個端點,並首先發送內容類型,然後讓客戶端使用與內容類型對應的端點。這是一個非常糟糕的黑客攻擊,將很多這種邏輯轉移到客戶端,我覺得應該更好地處理服務器。 – Ecognium

回答

3

這是可能的,但黑客攻擊的一位:

{-# LANGUAGE DataKinds #-} 
{-# LANGUAGE FlexibleContexts #-} 
{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE MultiParamTypeClasses #-} 
{-# LANGUAGE OverloadedStrings #-} 
{-# LANGUAGE OverlappingInstances #-} 
module DynCT where 

import Control.Monad.Trans.Either 
import Data.ByteString.Lazy (ByteString) 
import Servant 
import Servant.API.ContentTypes 
import Network.Wai.Handler.Warp 

data WithCT = WithCT { header :: ByteString, content :: ByteString } 

instance AllCTRender xs WithCT where 
    handleAcceptH _ _ (WithCT h c) = Just (h, c) 

type API = Get '[] WithCT 

api :: Proxy API 
api = Proxy 

server :: Server API 
server = return $ WithCT { header = "example", content = "somecontent" } 

main :: IO() 
main = run 8000 $ serve api server 

測試它:

% curl localhost:8000 -v 
... 
< HTTP/1.1 200 OK 
... 
< Content-Type: example 
< 
... 
somecontent% 

該想法只是通過聲明AllCTRender的重疊實例來覆蓋正常行爲。請注意,如果你也使用這些,你可能還需要爲servant-clientservant-docs等做一些額外的工作。鑑於此,您可能希望在回購中提出有關此問題的更全面支持問題。

+0

非常感謝。這確實有效。我正在使用'servant-docs',並且出現類型錯誤。你已經知道這將是一個問題。不知道我需要提供什麼來滿足使用''[]'的文檔。我得到的錯誤是'無法推論(Servant.API.ContentTypes.IsNonEmpty'[])由於使用'Doc.docs''而引起的。我會開一個問題,看看是否有一個乾淨的方式來解決文檔問題。 – Ecognium

+0

我使它與文檔一起工作。而不是使用''[]'我只是使用了一個通用的自定義MIME類型。 Accept實例的內容類型正在被'AllCTRender'覆蓋,因此可以很好地工作。這樣我就可以使用文檔並返回一個自定義MIME類型。 – Ecognium