Search code examples
javascriptreactjsxmlhttprequestgoogle-cloud-storagegsutil

Image Upload Issue using gcs Upload Signed URL | React JS


Using this for to generate GCS Upload signed url v4 https://github.com/GoogleCloudPlatform/python-docs-samples/blob/master/storage/cloud-client/storage_generate_upload_signed_url_v4.py#L27

I have generated upload signed url using this function "generate_upload_signed_url_v4" as mentioned above and also I tried using GSUTIL as well using gsutil signurl -m PUT service_account.json gs://<bucket>/file.png I am working on a demo where I need to upload PDF, PNG to GCS bucket. File uploading is file. But when I preview file in GCS Storage Console and download/preview file form Link URL
PDF is fine. But PNG somehow got damaged and not opening/previewing. I am using Chrome '81.0.4044.138'

When I further preview PNG file using text editor it contains some header content at the top of file. i.e ------WebKitFormBoundarysZ3BDVaNOhqwENsp Content-Disposition: form-data; name="file"; filename="test.png" Content-Type: image/png So if we remove this from top of file the file will open fine..

I have created a sample React project which can be accessed here

Demo: https://github.com/qaisershehzad/upload-gcs

I am using this code for file upload

` const url = "https://storage.googleapis.com//file.png.png?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=gitlab-ci%.iam.gserviceaccount.com%2F20200521%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20200521T175304Z&X-Goog-Expires=36000&X-Goog-SignedHeaders=content-type%3Bhost&X-Goog-Signature="

const data = new FormData()
data.append('file', this.state.selectedFile)

var xhr = new XMLHttpRequest();

xhr.open('PUT', url, true);
xhr.setRequestHeader("Content-type", "application/octet-stream");


xhr.onload = function (response) {
  console.log('on-load', response);
};

xhr.onreadystatechange = function () {
  if (xhr.readyState === 4) {

    if (xhr.status === 200) {
      console.log("Status OK")

    } else {
      console.log("Status not 200")
    }
  }
};

xhr.onerror = function (response) {
  console.log("Response error", response)
};

xhr.upload.onprogress = function (evt) {
  // For uploads
  if (evt.lengthComputable) {
    var percentComplete = parseInt((evt.loaded / evt.total) * 100);
    console.log("progress", percentComplete)

  }
}
xhr.send(data);`

I also tried same thing on Android as well and facing same issue. In Png at top these header string got added which not allowing to open Png file.

Png uploading is working fine using this CURL request. curl -X PUT -H 'Content-Type: application/octet-stream' --upload-filen file.png 'https://storage.googleapis.com//file.png?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=gitlab-ci%.iam.gserviceaccount.com%2F20200521%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20200521T175304Z&X-Goog-Expires=36000&X-Goog-SignedHeaders=content-type%3Bhost&X-Goog-Signature='

It will be helpful if someone can help to resolve this issue.


Solution

  • Actually you are sending FormData which causes a problem, you will see file get uploaded but when you retrieve file its content will be different in case of image possibly image will not get rendered.

    The reason why cURL is working, because you are directly sending file not FormData.

    To fix this scenario directly pass the file to ajax like mentioned below:

    const file = this.state.selectedFile;
    
    ajax.setRequestHeader('Content-Type', file.type);    
    ajax.send(file); // direct file not FormData