我正在使用 Servant 在 Haskell 中开发一个 Web 应用程序。我成功在服务器上加载文件并将它们移动到我的 SFTP 服务器。现在我希望用户能够在 SFTP 上加载文件(我需要用servant为他们提供静态文件)。为了管理 CORS 问题,我使用了 WAI 中间件库。这是我的代码,我在其中引入中间件来设置 CORS 标头。
newtype Welcome
= Welcome {
greeting :: String
}
deriving (Generic, Eq, Show)
instance ToJSON Welcome
instance FromJSON Welcome
welcomeMesg :: Welcome
welcomeMesg = Welcome "Mbote Ba'a Mpagi!"
type API =
-- | test for home page
"home" -- 1
:> Get '[JSON] Welcome
:<|> "tenants"
:> Capture "tenantid" Text
:> "informations"
:> MultipartForm Tmp (MultipartData Tmp)
:> Post '[JSON] (GenericRestResponse InformationCreated ConstructionError)
:<|> "tenants" -- 3
:> Capture "tenantid" Text
:> "informations"
:> Capture "informationid" Text
:> "documents"
:> Raw
addOriginsAllowed :: Response -> Response
addOriginsAllowed =
let final = (:) ("Access-Control-Allow-Origin", "*") .
(:) ("Access-Control-Allow-Methods", "GET, POST, PUT, OPTION") .
(:) ("Access-Control-Allow-Headers", "Content-Type, Authorization")
in mapResponseHeaders final
addAllOriginsMiddleware :: Application -> Application
addAllOriginsMiddleware baseApp req responseFunc =
let newResponseFunc :: Response -> IO ResponseReceived
newResponseFunc = responseFunc . addOriginsAllowed
in baseApp req newResponseFunc
startApp :: IO ()
startApp = run 9080 $ addAllOriginsMiddleware app
proxy :: Proxy API
proxy = Proxy
optionMidlleware :: Middleware
optionMidlleware = provideOptions proxy
app :: Application
app = optionMidlleware $ serve proxy routes
routes :: Server API
routes =
return
welcomeMesg -- 1
:<|> handleCreateInformation --2
:<|> handlerGetInformationDocuments -- 3
如果我没有明确要求
Raw
提供静态文件,一切都会正常运行。最后一个 enpoint 生成此错误:
• No instance for (servant-foreign-0.16:Servant.Foreign.Internal.GenerateList
Servant.API.ContentTypes.NoContent
(http-types-0.12.4:Network.HTTP.Types.Method.Method
-> servant-foreign-0.16:Servant.Foreign.Internal.Req
Servant.API.ContentTypes.NoContent))
arising from a use of ‘provideOptions’
(maybe you haven't applied a function to enough arguments?)
• In the expression: provideOptions proxy
In an equation for ‘optionMidlleware’:
optionMidlleware = provideOptions proxytypecheck(-Wdeferred-type-errors)
provideOptions :: forall api.
(GenerateList NoContent (Foreign NoContent api),
HasForeign NoTypes NoContent api) =>
Proxy api -> Middleware
Defined in ‘Network.Wai.Middleware.Servant.Options’ (servant-options-0.1.0.0)
_ :: Proxy API -> Middleware
这个错误发生在我调用
provideOptions
(WAI中间件库的函数)的地方
我被屏蔽了。我能做什么来克服这个错误。 预先感谢您的帮助
我尝试返回 ByteString 但 i 不是 ToJson 和 FromJson 的实例
发生此错误是因为
Raw
端点只是非 Servant 请求/响应处理的“逃生舱口”,因此 provideOptions
(Servant 特定的中间件)无法正确处理 Raw
API 中的端点。
更详细地说,
provideOptions
使用特定于端点的HasForeign
实例来查询API以获取支持的方法,以便构建正确的Allow
标头来响应OPTIONS
请求。它可以对所有 Servant 端点执行此操作,除了Raw
,它没有 HasForiegn
实例。
也许可以在您的特定情况下找到一些工作,但我的猜测是您根本不需要
Raw
端点。 Servant 说明书中的示例使用 Raw
端点来提供静态文件,但这仅仅是因为它们想要使用本质上非 Servant 处理函数 (serveDirectoryWebApp
) 来提供整个目录。 (是的,serveDirectoryWebApp
是在servant-server
包中定义的,但它实际上是一个非Servant处理程序。它并没有真正使用Servant API或任何Servant处理程序设施。它只是来自serveDirectoryWith
的
Network.Wai.Application.Static
的包装器。)
在您的情况下,听起来您只是想编写一个简单的Servant处理程序
handlerGetInformationDocuments
,它直接访问文件并将其内容收集在ByteString
中,并且您希望提供该ByteString
作为内容响应客户的 GET
请求而返回。如果是这样,您只需要一个返回八位字节流的 Raw
端点,而不是 Get
端点,例如:
import qualified Text.ByteString.Lazy as LBS
... :> "documents" :> Get '[OctetStream] LBS.ByteString
处理程序只需返回
ByteString
:
handlerGetInformationDocuments :: Text -> Text -> Handler LBS.ByteString
handlerGetInformationDocuments tenantid informationid = do
content <- liftIO $ LBS.readFile "file.bin"
pure content
上面,我使用了惰性
ByteString
,如果文件有点大,这可能是最好的,尽管您要注意在开始提供文件后不要修改文件。严格的 ByteString
也可以很好地工作,尤其是在文件很小的情况下。