Czym właściwie jest Base64
Base64 to schemat kodowania binarnego na tekst, czyli sposób zapisania dowolnych danych binarnych 64 znakami, które przechodzą bez szwanku przez systemy przystosowane do liter. Algorytm bierze trzy bajty wejścia (24 bity), dzieli je na cztery grupy 6-bitowe i każdą grupę zamienia na jeden znak z tablicy kodującej. Jeżeli na końcu zostanie jeden lub dwa bajty, wynik uzupełnia się znakami =, żeby długość pozostała podzielna przez cztery.
Z tej arytmetyki wynika stały koszt: cztery znaki wyjścia na każde trzy bajty wejścia, czyli około 33% więcej danych. Dlatego załącznik w wiadomości e-mail zajmuje w skrzynce więcej miejsca niż ten sam plik na dysku - poczta przenosi go właśnie w Base64.
Tablica kodująca wygląda tak samo w każdej implementacji, od A-Z i a-z, przez cyfry 0-9, po + i / na dwóch ostatnich pozycjach. Wszystkie 64 pozycje należą do drukowalnych znaków ASCII, więc gotowy ciąg reprezentuje dane binarne w postaci, którą można wkleić w zwykły tekst i przenieść przez kanał znający wyłącznie siedmiobitowy alfabet.
Jak kodować i dekodować polskie znaki
Wbudowana w przeglądarki funkcja JavaScriptu btoa przyjmuje wyłącznie znaki o kodach 0-255. Litera „ż” ma w Unicode numer 380, więc próba zakodowania słowa „żaba” kończy się wyjątkiem InvalidCharacterError. To najczęstsza przyczyna, dla której prosty koder Base64 działa po angielsku, a wysypuje się po polsku.
Base64 koduje zawsze bajty i konwertuje tekst dopiero wtedy, gdy ten tekst zostanie wcześniej zamieniony na bajty UTF-8. Litera „ż” to w UTF-8 dwa bajty o wartościach C5 i BC, a oba mieszczą się w zakresie 0-255, więc btoa nie ma z nimi kłopotu. Przy dekodowaniu przeglądarka robi to samo w odwrotnej kolejności. Z ciągu Base64 odzyskuje bajty, a z bajtów składa tekst przez TextDecoder. „Zażółć gęślą jaźń” wraca wtedy w całości, razem z ogonkami.
Base64URL, czyli wariant do adresów
Znaki + i / mają w adresach URL własne znaczenie. Pierwszy bywa interpretowany jako spacja, drugi rozdziela segmenty ścieżki. RFC 4648 opisuje więc drugi wariant formatu Base64, zwany Base64URL, w którym + zastępuje -, a / zastępuje _. Dopełnienie = zwykle się pomija, bo w adresie też wymaga kodowania procentowego.
Ten wariant spotkasz w tokenach JWT, w kluczach webhooków i w identyfikatorach zasobów. Dekoder Base64 w tym narzędziu przyjmuje obie odmiany jednocześnie. Zamienia - i _ z powrotem na znaki podstawowej tablicy, sam dopisuje brakujące dopełnienie i nie wymaga deklarowania wariantu przed wklejeniem danych.
Gdzie Base64 jest powszechnie używany
Base64 powstał na potrzeby poczty elektronicznej. Protokół SMTP w pierwotnej postaci przenosił wyłącznie siedmiobitowy tekst, a załącznik trzeba było jakoś przez niego przepchnąć, więc standard MIME opisał sposób przesyłania danych binarnych w postaci liter i cyfr. Ten sam mechanizm jest dziś powszechnie używany wszędzie tam, gdzie kanał przyjmuje tylko ciągi znaków: obrazek osadzony w arkuszu stylów, plik wetknięty w pole JSON-a albo w dokument XML, certyfikat serwera zapisany w formacie PEM.
Drugie duże zastosowanie to nagłówki HTTP. Uwierzytelnianie Basic wysyła login i hasło sklejone dwukropkiem, a potem zakodowane w Base64, co bywa mylone z zabezpieczeniem. Odwrócenie takiego nagłówka zajmuje sekundę w tym narzędziu, a poufność zapewnia dopiero HTTPS, czyli szyfrowanie całego połączenia. Klucze API i tokeny sesji korzystają z Base64 z tego samego powodu, bo taki zapis nadaje się do przesyłania danych przez systemy, które zmieniają albo obcinają bajty spoza ASCII.
Data URI i granica opłacalności
Data URI to zapis w postaci data:typ/podtyp;base64,zawartość, który wkleja plik bezpośrednio w kod strony. Base64 konwertuje wtedy zawartość pliku na tekst, więc obrazek mieszka w tym samym arkuszu stylów co reguły, które się do niego odwołują. Znika osobne zapytanie do serwera, a zasób zawsze jest pod ręką, bo stał się częścią dokumentu. Sprawdza się to przy małych ikonach SVG i wzorkach tła o rozmiarze kilku kilobajtów.
Wady ujawniają się przy większych plikach. Zakodowany obrazek jest o jedną trzecią cięższy, ląduje w tym samym pliku CSS lub HTML co reszta kodu i nie może być zapisany w pamięci podręcznej osobno, więc każda zmiana strony wymusza ponowne pobranie całości. Praktyczna granica opłacalności leży w okolicy kilkunastu kilobajtów.
Dekoder Base64 i najczęstsze błędy
Najczęstszy komunikat, jaki zobaczysz, dotyczy niedozwolonych znaków. Zwykle winny jest cudzysłów skopiowany razem z ciągiem albo fragment data:image/png;base64, zostawiony przed właściwymi danymi. Białe znaki, w tym złamania wierszy, są nieszkodliwe, bo usuwamy je przed dekodowaniem.
Drugi przypadek to niepoprawna długość, bo ciąg Base64 po dopisaniu dopełnienia musi dzielić się przez cztery, a reszta równa jeden jest matematycznie niemożliwa i oznacza dane ucięte w połowie. Trzeci przypadek wygląda groźniej, niż jest. Dekoder zamienia Base64 z powrotem na bajty poprawnie, tylko te bajty nie były tekstem, więc na ekranie pojawiają się przypadkowe znaki. Takie dane lepiej przekonwertować w zakładce „Base64 → plik”, która rozpozna typ zawartości po sygnaturze pierwszych bajtów.