Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Upload file directly to Azure Blob Storage (with SAS) using dropzone.js

I would like to use dropzone.js to upload files directly to Azure Blob Storage, with SAS (example here) to keep the files private.

As I understand it, the workflow would be:

  1. The user chooses a file
  2. The dropzone processing event fires. In the event handler, I call a method on my site's API which creates an Azure Blob URI to upload to, including the SAS query string
  3. The dropzone upload URL is set to the "secured" blob URL
  4. The upload begins

I have found the following wiki article showing how to set the dropzone URL dynamically (https://github.com/enyo/dropzone/wiki/Set-URL-dynamically)

Dropzone.options.myDropzone = {
  init: function() {
    this.on("processing", function(file) {
      // I need to do an async call here, to get the URL...
      this.options.url = "/some-other-url";
    });
  }
};

The problem is that the above example is synchronous. How can I delay the upload until the URL has been requested from my web api asynchronously?

Thanks

like image 688
Matt Wilson Avatar asked Feb 17 '16 12:02

Matt Wilson


People also ask

How do I automatically upload files to Azure Blob storage?

Create Power Automate Desktop Flow Go to containers and create a new container. Open the container and on the and navigate to Shared access signature. Select add, create, and write permission, change the time if needed, and press Generate SAS token and URL. Copy the Blob SAS URL and save it as the variable in the flow.

How do I upload files to Azure Blob storage using API?

Upload contents of a folder to Data Box Blob storage To get your account key, in the Azure portal, go to your storage account. Go to Settings > Access keys, select a key, and paste it into the AzCopy command. If the specified destination container does not exist, AzCopy creates it and uploads the file into it.


2 Answers

May be I am a bit late with answer

Use predefined SAS

Just save it in form element with data-sas attribute while rendering a page. The only drawback I see — your SAS could expire if page haven’t refreshed for a while. This is a part from my working code (other variants are from my head)

Dropzone.options.myDropzone = {
  method: "PUT",
  headers: {"x-ms-blob-type": "BlockBlob"},
  sending: (file, xhr) => {
    // To send file without wrappintng it to multipart/form-data,
    // Azure won’t unwrap it
    const _send = xhr.send;
    xhr.send = () => { _send.call(xhr, file) };
  },
  init: function() {
    const dz = this,
          action = dz.element.action,
          sas = dz.element.dataset.sas;

    dz.on("processing", (file) => {
      dz.options.headers["Content-Type"] = file.type;
      dz.options.url = `${action}/${file.name}?${sas}`;
    })
  },
}

Use async call in Dropzone’s init

Dropzone.options.myDropzone = {
  autoProcessQueue: false, // To prevent automatic auploading before getting SAS
  acceptedFiles: ".xls,.xlsx",
  method: "PUT",
  headers: {"x-ms-blob-type": "BlockBlob"},
  sending: (file, xhr) => {
    // To send file without wrappintng it to multipart/form-data,
    // Azure won’t unwrap it
    const _send = xhr.send;
    xhr.send = () => { _send.call(xhr, file) };
  },
  init: function() {
    let sas = null;
    const dz = this,
          xhr = new XMLHttpRequest();

    xhr.addEventListener("load",
        (event) => {
          sas = getSasFromEvent(event);
          dz.options.autoProcessQueue = true;
          dz.processQueue();
        }, true);
    xhr.open("GET", "/get-sas");
    xhr.send();

    dz.on("processing", (file) => {
      dz.options.headers["Content-Type"] = file.type;
      dz.options.url = `${action}/${file.name}?${sas}`;
    })
  },
}

Run Dropzone after you’ve got a SAS asynchrouniosly

See Create dropzones programmatically

like image 170
voldmar Avatar answered Oct 22 '22 04:10

voldmar


You could try a synchronous ajax call using jQuery.

function GetUrl() {
    var url = "";
    $.ajax({
        async: false,
        success: function(data) {
            url = data;
        }
        // Other opts   
    });
    return url;
}

Dropzone.options.myDropzone = {
  init: function() {
    this.on("processing", function(file) {
      this.options.url = GetUrl();
    });
  }
};
like image 21
jbell Avatar answered Oct 22 '22 05:10

jbell