3

Situation: You need to download a pdf file (or any file type) from firebase storage to your computer via browser that has a vue.js web app (contains vuetify). You have looked at the firebase storage doc, but it isn't crystal clear. You are not sure about the right firebase storage rules for you. This is for frontend - the user's browser. How shall you implement this?

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Tenzin Thabkhae
  • 75
  • 1
  • 10

1 Answers1

1

This is a compilation answer on how to download files from firebase storage to user's computer via a vue web app. The firebase storage download documentation has 90% of what you need for your vue.js web app to download a file to your computer. Follow the steps there. If you are not using firebase authentication, then you might want to set read access to everyone. By default, only authenticated users can read and write. You can do so like this in your firebase storage rule:

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read: if request.auth == null;
      allow write: if request.auth != null;
    }
  }
}

This lets anyone view/download your files. Next, by following the guide posted above, you will be able to get the url of the file, then convert it into 'blob' format. Now, the guide doesn't tell you what to do next but another Stack Overflow answer has the solution. I have combined the two here. Basically what happens in the code is:

  1. You should call the event handler function from @click.prevent event emitter instead of @click.
  2. The event handler function does several things. Like the firebase storage documentation, it gets the url of your file and converts it into a 'blob' via XMLHttpRequest().
  3. Following the linked solution, you should create a new a element, then assign its href attribute to the 'blob', download name and emit the click event. Revoke the href attribute after to avoid accidents.

Traditionally, we use a links to download files but we can use v-btn as we are creating the a link in the event handler. My button has a tooltip and icon. Also, due to linter I removed unuses variables.


Inside html template:

<v-tooltip top>
  <template v-slot:activator="{ on, attrs }">
    <v-btn
      :color="counterThemeColorClass"
      fab
      ripple
      v-bind="attrs"
      v-on="on"
      @click.prevent="downloadResumePdf"
    >
    <v-icon
      :color="themeColorClass"
      x-large
    >mdi-file-account-outline</v-icon>
    </v-btn>
  </template>
  <span class="font-weight-bold">download resume</span>
</v-tooltip>

Inside script:

downloadResumePdf() {
  const resumeRef = firebase.storage()
    .ref('tenzin_resume.pdf');
  resumeRef.getDownloadURL().then((url) => {
    // `url` is the download URL
    console.log(url);
    // This can be downloaded directly:
    const xhr = new XMLHttpRequest();
    xhr.responseType = 'blob';
    xhr.onload = function () {
      const blob = xhr.response;
      const link = document.createElement('a');
      link.href = URL.createObjectURL(blob);
      link.download = 'tenzin_resume';
      link.click();
      URL.revokeObjectURL(link.href);
    };
    xhr.open('GET', url);
    xhr.send();
  }).catch((error) => {
    // Handle any errors
    switch (error.code) {
      case 'storage/object-not-found':
        // File doesn't exist
        break;

      case 'storage/unauthorized':
        // User doesn't have permission to access the object
        break;

      case 'storage/canceled':
        // User canceled the upload
        break;

      case 'storage/unknown':
        // Unknown error occurred, inspect the server response
        break;
      default:
        break;
    }
  });
},

Tenzin Thabkhae
  • 75
  • 1
  • 10