2

I am trying to upload a picture using thymeleaf ajax and spring-boot. I have used most of the post i found on stackoverflow and other forums but i does seem to work. i have add CSRF on my security configuration and also included it in the ajax upload script, but still facing the "400 (Bad Request)" error.

Exception error

017-03-01 23:50:06.893 ERROR 58753 --- [nio-8080-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is org.apache.commons.fileupload.FileUploadException: Stream closed] with root cause

java.io.IOException: Stream closed
    at org.apache.catalina.connector.InputBuffer.read(InputBuffer.java:372) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:190) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
    at java.io.FilterInputStream.read(FilterInputStream.java:133) ~[na:1.8.0_65]
    at org.apache.commons.fileupload.util.LimitedInputStream.read(LimitedInputStream.java:134) ~[commons-fileupload-1.3.2.jar:1.3.2]
    at org.apache.commons.fileupload.MultipartStream$ItemInputStream.makeAvailable(MultipartStream.java:999) ~[commons-fileupload-1.3.2.jar:1.3.2]
    at org.apache.commons.fileupload.MultipartStream$ItemInputStream.read(MultipartStream.java:903) ~[commons-fileupload-1.3.2.jar:1.3.2]
    at java.io.InputStream.read(InputStream.java:101) ~[na:1.8.0_65]
    at org.apache.commons.fileupload.util.Streams.copy(Streams.java:100) ~[commons-fileupload-1.3.2.jar:1.3.2]
    at org.apache.commons.fileupload.util.Streams.copy(Streams.java:70) ~[commons-fileupload-1.3.2.jar:1.3.2]
    at org.apache.commons.fileupload.MultipartStream.readBodyData(MultipartStream.java:593) ~[commons-fileupload-1.3.2.jar:1.3.2]

Upload

<form id="upload-file-input" th:action="@{/uploadFile}" method="post" th:object="${picture}" enctype="multipart/form-data" class="form-inline inline new-item">
        <div th:replace="common/layout :: flash"></div>
        <fieldset>
            <legend> Upload Picture</legend>
        <div class="row">
            <div class="col s12 l8">
                <div class="file-wrapper">
                    <input type="file" id="file" name="uploadfile"/>
                    <span class="placeholder" data-placeholder="Choose an image...">Choose an image...</span>
                    <label for="file" class="button">Browse</label>
                    <span id="upload-file-message"></span>
                </div>
            </div>
            <button type="submit" class="btn btn-primary">Upload</button>
        </div>
        </fieldset>
        <div class="style16"></div>
    </form>

upload controller

@RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
    @ResponseBody
    public String uploadFile(@RequestParam("uploadfile") MultipartFile uploadfile) {

        try {
            // Get the filename and build the local file path
            String filename = uploadfile.getOriginalFilename();
            String directory = "/Sites/admissionsPortal/data";
            String filepath = Paths.get(directory, filename).toString();

            // Save the file locally
            BufferedOutputStream stream = new BufferedOutputStream(new FileOutputStream(new File(filepath)));
            stream.write(uploadfile.getBytes());
            stream.close();
        }
        catch (Exception e) {
            System.out.println(e.getMessage());
        }

        return "redirect:/cert_prog";
    } // method uploadFile

Upload.js

var token = $("meta[name='_csrf']").attr("content");
$.ajaxSetup({
    beforeSend: function(xhr) {
        xhr.setRequestHeader('X-CSRF-TOKEN', token);
    }
});

var $form = $("#upload-file-input");
  $form.on("submit", function(e){
   e.preventDefault();
   $.ajax({
           url: $form.prop('action'),
           type: "POST",
           data: new FormData($("#upload-file-input")[0]),
           enctype: 'multipart/form-data',
           processData: false,
           contentType: false,
           cache: false,
           success: function () {
             // Handle upload success
             $("#upload-file-message").text("File succesfully uploaded");
           },
           error: function () {
             // Handle upload error
             $("#upload-file-message").text("File not uploaded (perhaps it's too much big)");
           }
         });
     });
3
  • Do you ever hit the exception? Commented Mar 1, 2017 at 23:47
  • @MattClark Yes i do Commented Mar 1, 2017 at 23:51
  • @MattClark threw an IOException Commented Mar 2, 2017 at 0:00

3 Answers 3

1

The root cause of your error seems to be

nested exception is org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request

Which leads me to believe that your server side is working as intended, but the client is not sending data in the expected format.

Could you try changing up your ajax call to the following

// create a new form
var formData = new FormData();

// add your binary value to the file key
formData.append("file", fileBinary);


$.ajax({dataType : 'json',
    ...
    data : formData,                // add the form
    ...

Then on the server side, the uploaded file object will be present in the file parameter

public String uploadFile(@RequestParam("file") MultipartFile uploadfile) {
Sign up to request clarification or add additional context in comments.

1 Comment

I add the value to formData.append("file", $('input[type="file"]')[0]).val(); but got an error rg.springframework.web.multipart.MultipartException: The current request is not a multipart request –
0

Try to get formData like this

let uploadFile = $('#upload-file-input')[0];
let formData = new FormData(uploadFile);

send this formData in ajax data attribute.

Comments

0

The cause of the issue is java.io.IOException: Stream closed. Most likely this means that some code has already called close() on HttpServletRequest's InputStream before multipart request parsing started.

A likely culprit can be a flawed implementation of servlet Filter that wraps the request with a caching decorator (that uses cached request content for most operations, except for multipart processing) and closes the input stream before passing the decorated request for further processing.

Debugging to see what calls close on HttpServletRequest's InputStream should reveal the culprit.

If that is difficult for some reason, you can also try disabling any third party filters (various validating, logging, monitoring filters, etc.) and see if the problem persists.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.