3.4 Začínáme s  Firebase V9 vážně – Cloud Storage:Vzory kódu pro nahrávání souborů, reference, mazání, načítání a stahování

Poslední revize:srpen 2022

Úvod

Nahrání souboru na hostitelský server je běžným požadavkem webové aplikace – například uživatelé aplikace Blog mohou chtít mít možnost přidávat do svých příspěvků soubory grafiky nebo videa.

Dříve v této sérii příspěvků jste viděli, jak Firebase deploy postup lze použít k nahrání statického aktiva na server. Ale tady mluvíme o dynamickém aktiva. Firebase deploy v této situaci nebude k ničemu. Odpovědí společnosti Google na tento požadavek je služba nazvaná „Cloud Storage“.

Pokud jste byli pozorní, možná jste si toho všimli, když jste poprvé viděli konzolu Firebase v konfiguraci projektu Firebase. V té době se pozornost soustředila na Authentication, Firestore a Hosting, ale na seznamu karet "Build" v levém sloupci jste možná zahlédli službu označenou "Storage".

Otevřete Firebase Console pro svůj projekt, najděte kartu „Úložiště“ a klikněte na ni.

Cloud Storage je ve skutečnosti obrovskou součástí systému Google Cloud – na Cloud Storage for Firebase můžete nahlédnout do celkové vize Google pro tuto službu. V tomto příspěvku využiji jen zlomek jeho schopností, ale rychle uvidíte, že jde o zařízení, na které se můžete spolehnout, že splní všechny vaše požadavky na robustní, škálovatelné a bezpečné úložiště.

Cloudové úložiště je uspořádáno kolem úložných segmentů. Takto systém popisuje samotný Google:

Při prvním otevření stránky Úložiště konzoly vás Google požádá o inicializaci výchozího „bucketu“ úložiště, který byl přidělen vašemu projektu (název tohoto úložiště uvidíte, pokud otevřete Nastavení projektu a vyhledejte „storageBucket“)

Inicializace je obecně poměrně přímočará, ale můžete být lehce vyvedeni z míry, když se vás zeptá, zda chcete spustit svůj projekt v testovacím nebo produkčním režimu. Možná si však pamatujete, že něco podobného bylo, když jste inicializovali nastavení Firestore vašeho projektu – souvisí to s pravidly úložiště. V této fázi byste měli vybrat "test" - více o tom později. Vyberte si také vhodnou geografickou polohu – vaším cílem by mělo být někde přiměřeně blízko. Jakmile to všechno projdete, stránka Úložiště by měla vypadat nějak takto:

Nahrání souboru do cloudového úložiště

Pokud k tomuto příspěvku přicházíte s myslí plnou konceptů kolekce Firestore a nasazení kódu, můžete si představit, že jedním ze způsobů nahrání souboru může být uložení jeho obsahu do kolekce Firestore. Takže by vás například mohlo zajímat, zda byste jej mohli uložit do datového pole naformátovaného jako nějaký druh kódovaného řetězce. No, možná, ale maximální velikost dokumentu Firestore je 1 MB a u většiny obsahu, který pravděpodobně budete chtít nahrát, to moc daleko nezajde. V plánu tedy musí být nahrání souborů do cloudového úložiště.

Pojďme vytvořit nějaký kód pro nahrání souboru přímo do výchozího kbelíku projektu. Zde je příklad. Pokud jste se k tomuto příspěvku dostali v důsledku sledování předchozí epizody této série, tento kód níže je určen k přepsání index.html a index.js soubory v firexptsapp projekt popsaný v příspěvku 3.1. Nejprve nějaké HTML pro vyžádání názvu souboru:


<body style="text-align: center;">

    <input type="file" id="fileitem">

    <script src="packed_index.js" type="module"></script>
</body>

Pokud nejste obeznámeni s HTML file vstupní typ, podívejte se do dokumentace Mozilly na <input type="file"> - poskytuje velmi elegantní způsob, jak spustit okno pro výběr souboru a uložit volbu uživatele do DOM.

A tady je index.js soubor pro nahrání vybraného souboru do cloudového úložiště:

import { initializeApp } from 'firebase/app';
import { getAuth, GoogleAuthProvider, signInWithPopup } from 'firebase/auth';
import { getStorage, ref, uploadBytes, deleteObject, getDownloadURL } from 'firebase/storage';

const firebaseConfig = {
    apiKey: "AIzaSyAPJ44X28c .... 6FnKK5vQje6qM",
    authDomain: "fir-expts-app.firebaseapp.com",
    projectId: "fir-expts-app",
    storageBucket: "fir-expts-app.appspot.com",
    messagingSenderId: "1070731254062",
    appId: "1:10707312540 ..... 61bd95caeacdbc2bf",
    measurementId: "G-Q87QDR1F9T"
};
const firebaseApp = initializeApp(firebaseConfig);

const provider = new GoogleAuthProvider();
const auth = getAuth();

const storage = getStorage();

window.onload = function () {
    document.getElementById('fileitem').onchange = function () { uploadFile() };
}

function uploadFile() {
    const file = document.getElementById('fileitem').files[0];
    const filename = document.getElementById('fileitem').files[0].name;
    const storageRef = ref(storage,filename );
    uploadBytes(storageRef, file).then((snapshot) => {
        alert('Successful upload');
    });
}

uploadFile() funkce v index.js se spustí, když uvidí obsah index.html 's fileitem změna pole. To signalizuje, že uživatel vybral soubor. Předtím uvidíte, že kód inicializuje a autorizuje webovou aplikaci přesně jako v předchozích příspěvcích, ale také importoval několik nových funkcí z firebase/storage modul.

První novou akcí je vytvoření pro vytvoření storage objekt pomocí nového getStorage funkce. storageBucket vlastnost v předchozím firebaseConfig deklarace říká getStorage že chci, aby můj nahraný soubor skončil v mém výchozím kbelíku „fir-expts-app.appspot.com“.

uploadFile() funkce, kterou jsem vytvořil pro skutečné nahrání vybraného souboru, je velmi jednoduchá. Nejprve vytvoří file proměnná obsahující podrobnosti o vybraném souboru odvozená od položky DOM pro vstupní pole HTML (files[0] znamená "získat podrobnosti pro první v seznamu vybraných souborů" - v tomto případě je stejně jen jeden, ale musíme to projít). Poté obnoví název vstupního souboru a vytvoří storageRef proměnná, která toto kombinuje se specifikací cílového segmentu z storage variabilní. file (tj. zdroj) a storageRef (tj. cílové) proměnné jsou pak všechny uploadBytes sady SDK funkce potřebuje nahrát můj soubor. Po dokončení se na obrazovce prohlížeče zobrazí výstražná zpráva.

Abych to uvedl do provozu, jednoduše otevřu svůj build_for_development.ps1 skriptu (viz příspěvek 3.1), vyberte jeho obsah a stiskněte F8. Jakmile je kód úspěšně „webpacked“ (teď je to nezbytné, protože používám modulární V9 Firebase SDK) a nasazen, mohu spustit webovou aplikaci s dodanou adresou URL (https://fir-expts-app.web.app v tomto případě). Pokud poté vyberu náhodný soubor, prohlížeč by měl odpovědět výstražnou zprávou „Úspěšné nahrání“ a pokud obnovím stránku úložiště Firestore pro svůj projekt, měl bych vidět, že nyní obsahuje kopii mého původního souboru. Mohu zkontrolovat, zda se jedná o správný soubor, kliknutím na jeho položku v konzole a poznamenáním si užitečné miniatury a metadat, která se poté zobrazí.

Pravděpodobně si teď říkáte „to je v pořádku, ale musím na své úložiště dát nějakou strukturu, musím vytvořit další kbelíky, abych toho dosáhl“. Odpověď je "ne nutně". Systém Cloud Storage je velmi rád, že do specifikace vašeho storageRef zahrnete struktury složek variabilní. Pokud jsem tedy například změnil kód výše na čtení

 const storageRef = ref(storage,"myFolder/" + filename );

můj nahraný soubor 'myFile' by byl vytvořen ve složce 'myFolder' v mém výchozím kbelíku. Všimněte si, že tuto složku nemusím vytvářet explicitně – pokud neexistuje, uploadBytes ji automaticky vytvoří. Podobně, pokud již existuje soubor se zadaným názvem, bude přepsán.

Vaše další otázka by mohla znít „tak proč bych někdy chtěl víc než můj výchozí kbelík?“. K tomu můžete také přidat „zejména proto, že další segmenty jsou k dispozici pouze pro placené projektové plány“.

Jedním z dobrých důvodů je, že oprávnění k souborům se uplatňují na segment, nikoli na základě souboru nebo složky. Předpokládejme, že chcete, aby některé soubory byly dostupné široké veřejnosti, zatímco jiné měly zůstat „tajné“, musely by být tyto dvě sady uloženy v samostatných kbelících. Pokud chcete další podrobnosti, pomůže vám zde Google Zveřejnit data. Pokud máte problémy s přidělováním veřejného přístupu, měli byste zkontrolovat, zda konzola Google přidělila vašemu bloku hlavní roli „allUsers“ „Firebase Viewer“ a zda je vašemu projektu přiřazena role „storage Legacy Bucket Reader“.

V případě, že učiníte chcete uložit své soubory do bucketu s názvem "my-bucket", změnili byste storageBucket odkaz v firebaseConfig číst

    storageBucket: "my-bucket", 

Odkazování na soubor v cloudovém úložišti

Jakmile vytvoříte soubor „myfile“ v segmentu „mybucket“, můžete na něj odkazovat prostřednictvím jeho adresy URL na adrese „https://storage.googleapis.com/mybucket/myfile. Můžete to použít například jako src z img nebo href z window.open() . Příležitostný uživatel může také otevřít adresu na kartě prohlížeče, ale toto je bod, kdy budete muset použít konzolu Google k nastavení veřejných oprávnění ke čtení, jak bylo zmíněno dříve – výchozí nastavení nového segmentu je „soukromé“.

Smazání souboru z cloudového úložiště

Smazání cloudového souboru s názvem myFile ve složce myFolder je jen variací na téma, které jste již viděli.

const target = myFolder + "/" + myFile;

function deleteFile(target) {
    const storageRef = ref(storage, target);
    deleteObject(storageRef).then(() => {
        // File deleted successfully
    }).catch((error) => {
        console.log("Oops - System error - code is " + error);
    });
}

K tomuto jsem přidal „úlovek“, abyste viděli, jak funguje vaše zpracování chyb.

Všimněte si, že v Cloud Storage není možné přejmenovat soubor. Musíte jej smazat a znovu vytvořit.

Načítání souboru z cloudového úložiště

Pokud potřebujete, načte obsah myFile, abyste jej mohli zpracovat v těle své webové aplikace, musíte provést volání XMLHttpRequest. Následující část kódu obnoví obsah souboru myCloudFile.txt do místní proměnné myCloudFileContent:

const target = "myCloudFile.txt";
var myCloudFileContent;

function downloadFile(target) {

    const file = getDownloadURL(ref(storage, target))
        .then((url) => {
            const xhr = new XMLHttpRequest();
            xhr.responseType = 'text';
            xhr.onload = (event) => {
                myCloudFileContent = xhr.response;
            };
            xhr.open('GET', url);
            xhr.send();
        })
        .catch((error) => {
            alert('Oops - download failed error = ' + error);
        });
}

Všimněte si, že downloadFile je asynchronní funkce. Pokud potřebujete počkat na příchod myCloudFileContent, musíte wait pro dokončení downloadFile v async funkce.

Stahování souboru z cloudového úložiště

Vrácení kopie souboru Cloud Storage do místního úložiště souborů je o něco složitější než cokoli, co jste dosud viděli, ale následující kód staví na výše popsaném uspořádání a dělá svou práci velmi uspokojivě.

const target = "myCloudFile.txt";

function downloadFile(target) {

    const file = getDownloadURL(ref(storage, target))
        .then((url) => {
            const xhr = new XMLHttpRequest();
            const a = document.createElement("a");
            xhr.responseType = 'text';
            xhr.onload = (event) => {
                const blob = xhr.response;
                a.href = window.URL.createObjectURL(new Blob([blob], { type: "text/plain" }));
                a.download = "myLocalFile.txt";
                a.click();
                alert('Successful download');
            };
            xhr.open('GET', url);
            xhr.send();
        })
        .catch((error) => {
            alert('Oops - download failed error = ' + error);
        });
}

Tento kód načte soubor „myCloudFile.txt“ z úložiště Cloud STorage a uloží jej do složky pro stahování jako „myLocalFile.txt“. Aby se soubor dostal do místního úložiště, kód vytvoří prvek kotvy ukazující na adresu cloudového úložiště souboru myCloudFile.txt a dynamicky aktivuje akci „stažení“ kotvy pomocí volání „click()“.

Informace o těchto technikách najdete na stránce Google Stahování souborů pomocí cloudového úložiště na webu a na praktické stránce 5 způsobů vytváření a ukládání souborů v JavaScriptu od Codeboxx.

Pravidla úložiště

Zbývá vyžehlit poslední vrásku. Protože klíče rozhraní API projektu jsou v podstatě veřejné, musí být úložiště Google Cloud Storage chráněno stejným druhem uspořádání „pravidel“, jaké jste viděli dříve v souvislosti se zabezpečením dokumentů Firestore.

Aktuálně platná pravidla můžete zobrazit kliknutím na kartu „pravidla“ na stránce Úložiště konzoly Firebase. Protože jsem inicializoval úložiště pro projekt fir-expts-app v „testovacím“ režimu, budou vypadat nějak takto:

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if
          request.time < timestamp.date(2022, 1, 17);
    }
  }
}

Ty říkají „dovolte komukoli cokoliv dělat, dokud je datum spuštění před 17. lednem 2022“. Inicializaci jsem spustil 18. prosince 2021, takže mi Google dal měsíc na to, abych se dal do pořádku. Po tomto datu, pokud sám nezměním pravidla, úplně odepřou přístup, dokud věci neopravím. Prozatím je nastavení „test“ v pořádku, ale z dlouhodobého hlediska byste pravděpodobně chtěli přidat funkci „přihlášení“, která vám umožní nahradit pravidlo něčím jako

      allow read, write: if request.auth!=null;

Další příspěvky v této sérii

Pokud vás tento příspěvek zaujal a rádi byste se o Firebase dozvěděli více, možná by stálo za to podívat se na index této série.