How can I post FileInfo to a web service using Yes

2019-05-07 01:56发布

问题:

I am working with the default Yesod scaffolding project.
I have created a page that displays a simple form to upload files.
(The form will likely be created on the client using Javascript.)
For brevity, the form has a single file input:

<form method="post" action=@{UploadR}>
   <input type="file" name="myfile">
   <button type="submit">

My objective is to process the form data and then upload the file to a web service.
I have no trouble processing the form, my concern is interacting with the web service.
For example, given the following Yesod handler:

postUploadR :: Handler Html
postUploadR = do
    mgr <- fmap httpManager getYesod
    fi  <- runInputPost $ ireq fileField "myfile"
    let fSource = fileSource fi
        fName   = fileName fi
    req <- parseUrl "http://webservice/upload"
    let areq = req { method = methodPost
                   , requestBody = requestBodySourceChunked fSource
                   }
    res <- httpLbs areq mgr
    defaultLayout $ do
      setTitle "file uploaded"
      [whamlet|
       <h3> Success
       <p> You uploaded #{fName}.
      |]

The webservice returns the error: fail post content-length, but everything else works as expected. Perhaps the server doesn't support a chunked request body?

回答1:

I think your guess about chunked request body is correct. What you need to do is:

  • Stream the uploaded contents into a temporary file.
  • Get the size of that file.
  • Use requestBodySource and provide the file length and its contents.

Fortunately, steps (1) and (2) can be handled quite easily by the sinkCacheLength function. You'll end up with something like:

(fSize, fSource) <- fileSource fi $$ sinkCacheLength