json - 如何在 Yesod 中编写一个接收文件/图像上传的 JSON 端点?

标签 json ajax haskell file-upload yesod

我看到很多帖子涉及编写表单小部件来处理图像上传,但我的 Yesod 服务器只是一个 JSON API。我将通过 Angular 文件上传接收 Post 请求。

最佳答案

一个简单的方法是将文件编码为 base64 数据,然后 然后将其作为 JSON 的一部分发送。但是这种方法的缺点是 它增加了数据大小。

例子:

#!/usr/bin/env stack
{- stack
     --resolver lts-6.24
     --install-ghc
     runghc
     --package yesod
     --package yesod-core
     --package persistent
     --package text
     --package aeson
     --package bytestring
     --package base64-bytestring
-}

{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleInstances#-}
{-# LANGUAGE OverloadedStrings#-}
{-# LANGUAGE ScopedTypeVariables #-}

import Control.Monad (join)
import Control.Applicative
import Data.Text (Text, unpack)
import qualified Data.Text.Lazy.Encoding
import Data.Typeable (Typeable)
import Text.Blaze.Html.Renderer.Utf8 (renderHtml)
import Yesod
import Data.Aeson
import Data.Aeson.Types
import qualified Data.ByteString as BS
import Data.ByteString (ByteString)
import qualified Data.ByteString.Base64 as BS
import qualified Data.Text.Encoding as T

data App = App

mkYesod
  "App"
  [parseRoutes|
/json/test TestR POST
|]

instance Yesod App where
  approot = ApprootStatic "http://localhost:3006"

instance RenderMessage App FormMessage where
  renderMessage _ _ = defaultFormMessage

data Test = Test {
      fileData :: Text,
      name :: String
} deriving (Show, Eq, Ord)

instance FromJSON Test where
    parseJSON (Object v) = Test <$>
                           v .: "fileData" <*>
                           v .: "name"
    parseJSON _ = empty

postTestR :: Handler TypedContent
postTestR = do
  testData :: Test <- requireJsonBody
  let fileData' = BS.decode (T.encodeUtf8 $ fileData testData)
  case fileData' of
    Left err -> error err
    Right dat -> liftIO $ BS.writeFile "/home/sibi/myfile" dat
  selectRep $ provideRep $ return emptyObject

main :: IO ()
main = warp 3006 App

执行时:

$ curl -H "Content-Type: application/json" -H "Accept: application/json" -X POST -d '{"fileData":"aGVsbG8gd29ybGQ=","name":"Filename"}' http://127.0.0.1:3006/json/test
$ cat /home/sibi/myfile
hello world

关于json - 如何在 Yesod 中编写一个接收文件/图像上传的 JSON 端点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41070813/

相关文章:

json - JSON 模式中的变量属性

json - 使用接口(interface)将 JSON 字符串解码为数组

javascript - 在 JavaScript es6 中返回 Promise

javascript - 如何抑制此 JavaScript 错误 : Exception : TypeError: $ ("j2t-temp-div"). down (".j2t_ajax_message") is undefined?

javascript - AJAX 安全规范

haskell - 在 Haskell 中,对 Lazy ByteString 调用 length 会强制将整个字符串放入内存吗?

json - JOLT模板中特殊字符 "@"的使用

php - 无法进行 json_decode

haskell - 为什么使用 fromMaybe 提取 IO (Maybe Bool) 执行两个 IO 操作

haskell - 在惰性和严格 ByteString 之间轻松切换