javascriptjavaspringfile-uploadcorrupt-data

Java: Image upload with JavaScript - File is damaged, corrupted or too large


I am using Spring Boot as backend server and I have a JavaScript frontend. For sending data between front- and backend I'm using the Axios library, which usually works pretty fine.

The Problem:
The image looks like this in the (Chrome) browser console: Console output It's a very very long alphanumeric string and that's what I send to the server with the following code:

static uploadFiles(files) {
    const data = new FormData();

    Object.keys(files).forEach(key => {
        data.append("files", new Blob([files[key]], { type: 'image/jpeg' }));
    });

    const url = API_URL + "uploadFiles";
    return axios.post(url, data, RestServices.getAuth({
        "Content-Type": "multipart/form-data;boundary=gc0p4Jq0M2Yt08jU534c0p"
    }));
}

I have no idea what the boundary thing does but it worked to receive a file in the backend tho...

On backend (spring) side I successfully receive an array of MultipartFiles:

@RequestMapping(value = "/uploadFiles", method = RequestMethod.POST)
@ResponseBody
public boolean uploadFiles(HttpServletRequest request, @RequestParam("files") MultipartFile[] files) throws IOException {
    String filePath = Thread.currentThread().getContextClassLoader().getResource("assets/images/").getFile();
    InputStream inputStream;
    OutputStream outputStream;
    for(MultipartFile file : files) {
        File newFile = new File(filePath + file.getOriginalFilename() + ".jpg");
        inputStream = file.getInputStream();

        if (!newFile.exists() && newFile.createNewFile()) {
            outputStream = new FileOutputStream(newFile);
            int read;
            byte[] bytes = new byte[1024];

            while ((read = inputStream.read(bytes)) != -1) {
                outputStream.write(bytes, 0, read);
            }
        }
        System.out.println(newFile.getAbsolutePath());
    }
    return true;
}

I've also tried it file.transferTo(newFile); instead of in- and outputstreams - which didn't work either.
After that I get the following output, which means that the image was saved successfully: /path/to/blob.jpg
If I check the path where the file was uploaded, there is a file named blob.jpg, but if I open it, the windows photo viewer has the following problem: Error in windows photo viewer I've opened the image before and after upload with notepad++:
Before upload: Image before upload (Byte Array) I think this is a byte array, but If I open the image after upload I get exactly the output of the browser. This means it didn't get converted to a byte array (correct me if I'm wrong) and I believe that's why it's a corrupt image...

My questions are:

I really tried everything which crossed my mind but I ran out of ideas.

Thanks for your help! :-)


I've read following *related* questions (but they **don't** have an answer):
[Question1][5], [Question2][6], and **many** more...


Solution

  • I've finally found an answer on my own!

    I think the problem was that I used the e.target.result (which is used to show the image on the frontend) but insted I had to use the JS File object. The standard HTML 5 file input fields return those File objects (as I've read here).

    The only thing I had to do now is to make a FormData object, append the File Object, set the FormData as Body and set the Content-Type header and that's it!

    const data = new FormData();
    data.append("files", fileObject);
    return axios.post(url, data, {
        "Content-Type": "multipart/form-data"
    });
    

    Those JS File Objects are recognized from Java as Multipart files:

    @RequestMapping(value = "/uploadFiles", method = RequestMethod.POST)
    @ResponseBody
    public boolean uploadFiles(HttpServletRequest request, @RequestParam("files") MultipartFile[] files) {
    
        boolean transferSuccessful = true;
    
        for (MultipartFile file : files) {
            String extension = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf('.'));
    
            String newFileName = genRandomName() + extension; //set unique name when saving on server
            File newFile;
    
            File imageFolder = new File(imageBasePath);
            //check if parent folders exist else create it
            if(imageFolder .exists() || imageFolder .mkdirs()) {
                while ((newFile = new File(imageFolder .getAbsolutePath() + "\\" + newFileName)).exists()) {
                    newFileName = genRandomName(); //generate new name if file already exists
                }
                try {
                    file.transferTo(newFile);
                } catch (IOException e) {
                    e.printStackTrace();
                    transferSuccessful = false;
                }
            } else {
                LOG.error("Could not create folder at " + imageFolder.getAbsolutePath());
                transferSuccessful = false;
            }
        }
        return transferSuccessful;
    }
    

    I hope this is helpful :)