2

I need to do a signed POST request from Angular to AWS API gateway and send multipart/form-data with document and additional parameters.

I create FormData that as follows:

const formData = new FormData();
formData.append('document', document, document.name);
formData.append('document_metadata', new Blob(
  [JSON.stringify(metaData)],
  {
    type: 'application/json'
  })
);

Now, to do a request to AWS Gateway, I need to sign the request with all attributes being sent as body, meaning I need to somehow pass FormData to signature. The problem is that you can't get values of FormData without them being streamed.

to do that, I used approach mentioned here Get HTTP Body of Form in JavaScript. So I stream the file, decode it's values and combine it. This gives me the string that would be send with the request and with it I can sign the request ( with the help of https://github.com/mar753/aws-signature-v4 ).

async getFormDataStream(formData: FormData) {
    const response = new Response(formData);
    const stream = response.body;
    const reader = stream.getReader();
    const decoder = new TextDecoder('utf-8');
    const parent = this;
    let tempData = '';

    const headers: Headers = response.headers;
    headers.forEach((value, key) => {
      if(key ==='content-type') {
        this.customContentType = value;
      }
    });

    await reader.read()
      .then(function processData(result) {
        tempData = tempData + decoder.decode(result.value);
        if (result.done) {
          parent.customFormData = tempData;
          console.log('stream done');
          return;
        }
        return reader.read().then(processData);
      })
      .catch((err) => {
        console.log('catch stream cancellation:', err);
      });
}

Now I create the headers and request:

const headers = { 
   headers: new HttpHeaders({
      'X-Amz-Date': signature['X-Amz-Date'],
      'X-Amz-Security-Token': user.sessionToken,
      'x-api-access-token': user.getJwtToken(),
      'x-api-id-token': user.getJwtToken(),
      'Content-Type': this.customContentType, // contentType with boundary is generated from stream
      authorization: signature.Authorization
  };
this.http.post(APIGatewayEndpoint, this.customFormData, header); // customFormData is generated with stream

Everything I did so far works, I pass the Authorization without a problem and save the file. But the problem is that everything except for .txt file gets corrupted and I can't open it. I have to guesses what might be wrong:

  1. Document gets corrupted while decoding it with stream and SpringBoot can't parse it correctly
  2. SpringBoot isn't parsing raw data correctly?

Any help regarding the above would be appreciated as I'm stuck without options at the moment.

ecoLogic
  • 75
  • 7

0 Answers0