12

I have the following JAVA controller:

    @RequestMapping(value = "/data/upload", method = RequestMethod.POST)
    public
    @ResponseBody
    void uploadData(@RequestParam("file") MultipartFile file) throws IOException {
        logger.info("Received File for Ingestion");
        dataUploadService.processData(file.getInputStream());
    }

Node server side code:

serviceCall(serviceCallRequestData, request, finalResponse) {
        logger.info('Making remote request: ' + JSON.stringify(serviceCallRequestData));

        let file = request.files['file']; // file: Object {name: "sample_aspect_review_upload.csv", encoding: "7bit", mimetype: "text/csv", mv: }
        let formData = new FormData();
        formData.append('file', Buffer.from(file.data));

        fetch(serviceCallRequestData.url, {
            method: serviceCallRequestData.requestObject.method,
            headers: serviceCallRequestData.requestObject.headers,
            body: formData
        }).then(response => {
            if (response.status !== 200) {
                logger.error(`Error while making http call requestData: ${JSON.stringify(serviceCallRequestData)}`);
                finalResponse.status(500).send('Internal server error');
                return;
            }

            return response.json();
        }).then((json) => {
            logger.info(`Returning response for aspect-review-file-upload: ${JSON.stringify(json)}`);
            finalResponse.status(200).send(JSON.stringify(json));
        }).catch((e) => {
            logger.error(`Error while making http call requestData: ${JSON.stringify(serviceCallRequestData)} error: ${JSON.stringify(e)}`);
            finalResponse.status(500).send('Internal server error');
        });
    }

Trying to upload a csv file like:

"product_id","review_id","aspect_id","rating","confidence_score","indices"
"pid","rid","aid",1,0.851955,"[{\"s\":0,\"e\":114,\"highlights\":[39,68]}]"

The upload happens easily from POSTMAN. See the below screenshot: enter image description here

Getting an error in JAVA: Received Unknown exception org.springframework.web.bind.MissingServletRequestParameterException: Required MultipartFile parameter 'file' is not present when I am not passing contentType header from React.

Getting an error in JAVA: org.apache.commons.fileupload.FileUploadException: the request was rejected because no multipart boundary was found when I am passing contentType header from React as 'Content-Type': 'multipart/form-data'

The same Node server side code for a JAVA dropwizard controller as:

    @POST
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    @Produces(MediaType.APPLICATION_JSON)
    public Response uploadFile(
            @FormDataParam("file") InputStream inputStream,
            @FormDataParam("file") FormDataContentDisposition fileDetail
    ) throws IOException {
        logger.debug("Request to upload data file-name: {}", fileDetail.getName());

        dataUploadService.processData(inputStream);
        return Response.ok().build();
    } 

works correctly.

What am I doing wrong?

5
  • What headers are you sending from node server? Did you include the "Content-Type": "multipart/form-data" header? Commented Jun 1, 2018 at 12:39
  • @TarunLalwani: I have clearly mentioned the errors that I am getting when sending data with "Content-Type" header Commented Jun 4, 2018 at 12:21
  • I see the current answer as changes required on your back-end side, are you looking for a fix to the front-end code to make it work or are you evaluating changing the backend also as an option? Commented Jun 4, 2018 at 12:23
  • @TarunLalwani: Would prefer a frontend change, as there is no issue with the API when I hit it from POSTMAN. Commented Jun 4, 2018 at 12:25
  • Can you put a socat in between your FE and BE and compare the two requests? tarunlalwani.com/post/… Commented Jun 4, 2018 at 12:28

3 Answers 3

4
+200

From curl of postman you can see the following command:

curl -i -X POST -H "Content-Type:multipart/form-data" -F "file=@\"/pathto/sample.csv\";type=text/csv;filename=\"sample.csv\"" 'http://localhost:8080/data/upload'

So i tried adding type=text/csv;filename=\"sample.csv\" in the form-data so this should work:

    let file = request.files['file'];
    let formData = new FormData();
    formData.append("file", Buffer.from(file.data), {
        filename: file.name,
        contentType: file.mimetype,
    });

    fetch(serviceCallRequestData.url, {
        method: serviceCallRequestData.requestObject.method,
        headers: serviceCallRequestData.requestObject.headers,
        body: formData
    }).then(response => {
        if (response.status !== 200) {}
    });
Sign up to request clarification or add additional context in comments.

Comments

3

Few speculations:

  1. In your REST endpoint definition you specify file to be request parameter which is used to extract parameters from the URI itself, while multipart file upload sits within the body of the POST request.

    Add consumes={} and instead of @RequestParam you can use @RequestBody annotation:

    @RequestMapping(value = "/data/upload", method = RequestMethod.POST,
      consumes = {"multipart/mixed", "multipart/form-data"}
    )
    void uploadData(@RequestBody MultipartFile file) //body will be the whole JSON payload
    

    OR even better use @RequestPart where you can name the element:

    @RequestMapping(value = "/data/upload", method = RequestMethod.POST,
      consumes = {"multipart/mixed", "multipart/form-data"}
    )
    void uploadData(@RequestPart (value="file") MultipartFile file) //gets file from JSON
    
  2. Provide options to FormData:

    form.append('file', Buffer.from(file.data), {
      filename: 'image1.jpg', // ... OR:
      filepath: 'photos/image1.jpg',
      contentType: 'image/jpeg',
      knownLength: 19803
    });
    
    form.submit('http://example.com/', function(err, res) {
      if (err) throw err;
      console.log('Done');
    });
    

Can you confirm (using something like WireShark) what exactly gets sent from React?

8 Comments

This did not solve the problem. After making these changes [@RequestPart] hitting the API from POSTMAN still worked but from the node server, it failed stating MultipartException just as mentioned above.
@User_Targaryen added consumes to spring's endpoint and options to React
wild guess , but i would focus on the pass-thru 'headers' in your node code. Reason - POST stack sometimes may add headers in addition to ones set by your code. these 'inferred' header vals < compression, lang, chuncking ... > are not always helping the process
@diginoise: On using @RequestBody MultipartFile file, the request came to the JAVA controller, but with file as null. Why?
Thanks for the hint about using options in FormData
|
0

I spent a couple of hours on this issue and I didn't expect the issue to be of a value I was passing and not something else as the message was declaring that the key is not exists: "Required request part 'images' is not present"

At the end I found out that I was passing an array of files and expecting it to work fine as in POSTMAN! But I had to loop through my array and push the same key every time to be as following..

formData.append('images', images[0]);
formData.append('images', images[1]);

Here's how my code looks like to accept an array of files

@RequestMapping(value = "/upload", headers = ("content-type=multipart/*"), method = RequestMethod.POST, consumes = { "multipart/mixed", MediaType.MULTIPART_FORM_DATA_VALUE })
    public ResponseEntity<?> addPicture(
      @RequestParam(value="images") MultipartFile[] images) throws IOException {

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.