2016-02-25 42 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