Haben Sie mit dem Base64-Format zu tun? Dann ist diese Website genau das Richtige für Sie! Nutzen Sie unser superpraktisches Online-Tool, um Ihre Daten zu kodieren oder zu dekodieren.

Base64-Kodierung in Ruby: Ein vollständiger Leitfaden

Ihre Daten haben ein Ziel, das ihr Aussehen nicht akzeptiert. Ein Bild, das in einem JSON-Dokument leben muss. Ein Token, das eine URL überqueren muss. Ein Anhang, der ein Protokoll überstehen muss, das für 7-Bit-Text entworfen wurde. Ein Geheimnis, das in einer Umgebungsvariablen sitzen muss, ohne das Quoting zu sprengen. An jedem dieser Orte wird irgendetwas dazwischen gleich Ihre Binary zerstören - und die Lösung hat einen Namen: Base64.

In Ruby lebt der ganze Job in einem Modul, das mit der Sprache ausgeliefert wird. Drei Encoder, nichts zu installieren, und eine Ausgabe, die Sie vor dem ersten Lauf bis auf das exakte Zeichen vorhersagen können. Diese Vorhersehbarkeit ist die Hälfte der Geschichte, die die meisten Leitfäden überspringen, denn Kodieren ist der Ort, an dem die Überraschungen ihre Gebühr kassieren: ein anhängendes Newline schleicht sich in Ihr JSON, ein Zeilenumbruch, den Sie nicht bestellt haben, zerreißt ein Token, und eine falsche Alphabetwahl ruiniert eine URL. Dieser Leitfaden geht alle drei Encoder durch, die Mathematik der Ausgabe und jeden Payload, den ein Ruby-Entwickler tatsächlich kodiert, damit die Überraschungen aufhören, Überraschungen zu sein.

Ein kurzer Refresher, bevor wir loslegen: Base64 schreibt Daten drei Bytes auf einmal um, gibt vier Zeichen aus einem 64-Zeichen-Alphabet aus, mit einem oder zwei =-Zeichen Padding, wenn die Eingabe nicht ohne Rest durch drei teilbar ist - und genau deshalb wird die Ausgabe etwa ein Drittel größer als die Eingabe. Die Startseite dieser Site deckt das Format gründlich ab, also hält dieser Artikel das Format-Gerede auf einen Atemzug und geht direkt an die Arbeit.

Welchen Encoder brauchen Sie?

Ruby gibt Ihnen drei Encoder, und die Wahl zwischen ihnen ist ein Drei-Fragen-Quiz: Darf die Ausgabe Zeilenumbrüche enthalten? Darf sie + oder / enthalten? Darf sie Padding enthalten? Hier ist die komplette Aufstellung:

Encoder Ausgabeform Zeilenumbrüche Padding Wann Sie greifen
Base64.strict_encode64(bin) eine Zeile, Standard-Alphabet nie immer vorhanden JSON, Tokens, APIs, Dateien - der sichere Standard
Base64.encode64(bin) mehrere Zeilen, Standard-Alphabet nach jeweils 60 Zeichen, plus ein anhängendes immer vorhanden E-Mail-Body und andere zeilenorientierte Textprotokolle
Base64.urlsafe_encode64(bin, padding: true) eine Zeile, Bindestrich-Unterstrich-Alphabet nie Ihre Wahl, standardmäßig an alles, was in eine URL, ein Cookie oder einen Identifier landet

Wenn Sie unter Zeitdruck entscheiden, lautet die kurze Antwort: strict_encode64 als Standard, urlsafe_encode64, wenn das Ergebnis in einer URL reisen wird, und encode64 nur, wenn die empfangende Seite ein Textprotokoll ist, das kurze Zeilen möchte. Alles unten erklärt, warum - und wo jede Wahl Sie still etwas kostet.

strict_encode64: Das Workhorse

Base64.strict_encode64 ist der Encoder, den Sie in der großen Mehrheit Ihres Codes tatsächlich verwenden. Er erzeugt exakt eine Zeile Ausgabe, immer mit korrektem Padding, aus dem Standard-Alphabet:

require "base64"
Base64.strict_encode64("hello world")
# => "aGVsbG8gd29ybGQ="
Base64.strict_encode64("s")
# => "cw=="

Und weil der Algorithmus deterministisch ist, können Sie die exakte Länge der Ausgabe aus der Eingabe vorhersagen - kein Raten, keine Off-by-one-Bugs in Ihren Datenbank-Spalten. Die Tabelle unten ist die komplette Arithmetik:

Eingabelänge Ausgabelänge Padding am Ende
3n Bytes (teilt ohne Rest) 4n Zeichen keins
3n + 1 Bytes 4n + 4 Zeichen zwei =
3n + 2 Bytes 4n + 4 Zeichen ein =

So werden aus 11 Bytes 16 Zeichen, aus 100 Bytes 136, und aus einer 1-Megabyte-Datei etwa 1,33 Megabyte Text. Dieses Drittel an Wachstum ist der Eintrittspreis für jeden Base64-Payload, den Sie verschicken, und es ist die Zahl, die Sie in der Hinterhand behalten sollten, wann immer eine Spalte, ein Cache oder ein API-Ratenlimit enger wird.

Base64.strict_encode64("123")
# => "MTIz"        3 Bytes hinein, 4 Zeichen heraus
Base64.strict_encode64("1234")
# => "MTIzNA=="   4 Bytes hinein, 8 Zeichen heraus, zwei Padding-Zeichen
Base64.strict_encode64("12345")
# => "MTIzNDU="   5 Bytes hinein, 8 Zeichen heraus, ein Padding-Zeichen

encode64: Der mit den Zeilenumbrüchen

Base64.encode64 ist der Klassiker, und er hat ein Verhalten, das schon so manchen Nachmittag beendet hat: Es bricht seine Ausgabe um. Alle 60 Zeichen beginnt es eine neue Zeile, und es endet immer mit einem anhängenden Zeilenumbruch:

Base64.encode64("hello world")
# => "aGVsbG8gd29ybGQ=\n"
Base64.encode64("*" * 46)
# => "KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq\nKg==\n"

Das Umbruch-Verhalten ist kein Bug - es ist ein Feature, das aus dem ursprünglichen Zuhause der Methode in der MIME-Welt geerbt wurde, wo lange Zeilen ein Protokollverstoß waren. Rubys mail-Gem stützt sich bewusst darauf - sein Base64-Encoder trägt sogar einen Kommentar dahingehend, dass Rubys Zeilenumbruch die Ausgabe innerhalb der SMTP-Zeilengrenzen hält. Wenn Sie E-Mail-Body kodieren, tut encode64 Ihnen einen Gefallen.

In jedem anderen Kontext aber ist das Umbruch-Verhalten eine Steuer. Der häufigste Unfall ist ein JSON-Dokument, in dem ein Base64-Wert plötzlich über zwei Zeilen geht:

payload = { "logo" => Base64.encode64(File.binread("logo.png")) }
puts payload.to_json
# der logo-Wert trägt Zeilenumbrüche, die niemand bestellt hat

Und der kleinere Zwillingsbruder desselben Bugs ist das anhängende Newline bei kurzen Strings: Base64.encode64("s") liefert "cw==\n", und ein Token, das Sie in eine URL kopieren oder mit einem erwarteten Wert vergleichen, schlägt fehl aus Gründen, hinter denen Sie zwanzig Minuten herlaufen werden. Das Gegenmittel ist ein strip - aber das bessere Gegenmittel ist strict_encode64, das nie ein einziges Zeichen hinzufügt, das Sie nicht verdient haben. Und es gibt eine charmante Asymmetrie, die es zu wissen lohnt: eine leere Eingabe erzeugt einen leeren String ohne anhängendes Newline, also ist Base64.encode64("") einfach nur "".

urlsafe_encode64: Das Link-sichere Alphabet

Zwei Zeichen im Standard-Alphabet verursachen überall Ärger, wo ein URL-Parser zuschaut: + (ein Leerzeichen in Query-Strings) und / (ein Pfadtrenner). RFC 4648 löste das mit einem Tausch - - nimmt den Platz von +, _ den Platz von / - und Ruby setzt es in Base64.urlsafe_encode64 um:

Base64.urlsafe_encode64("\xfb\xef\xbe".b)
# => "----"
Base64.urlsafe_encode64("\xff\xff\xff".b)
# => "____"

Diese beiden Beispiele sind das Alphabet in Aktion: dieselben Bytes, die der Standard-Encoder als ++++ oder //// rendert, kommen als ---- und ____ heraus, Zeichen, die URLs, Pfade, Dateinamen und Formularfelder ohne jede Percent-Encoding überstehen. Die Ausgabe ist eine Zeile, genau wie bei strict_encode64.

Die einzige Option der Methode ist das padding:-Keyword, hinzugekommen in Ruby 2.3, und es ist die, die man kennen sollte. Die JSON-Web-Token-Spezifikation verlangt base64url ohne Padding, und viele andere Token-Schemata ebenso:

Base64.urlsafe_encode64("*")
# => "Kg=="
Base64.urlsafe_encode64("*", padding: false)
# => "Kg"

Bei ausgeschaltetem Padding verschiebt sich die Längen-Mathematik: 3n + 1 Bytes ergeben jetzt 4n + 2 Zeichen, und 3n + 2 Bytes ergeben 4n + 3. Die Dekodierer-Seite kommt klar - Rubys urlsafe_decode64 hängt das fehlende Padding selbst an - also ist Ausgabe ohne Padding sicher zu erzeugen, aber Ausgabe mit Padding ist der freundlichere Standard, wenn die andere Seite ein strenger RFC-2045-Leser ist. Eine Warnung: Schalten Sie Padding nur dann aus, wenn eine Spezifikation es verlangt. Es spart ein oder zwei Zeichen und kauft Ihnen eine ganze Klasse von Dekodierer-Beschwerden ein.

Was Ruby tatsächlich kodiert: Strings sind Bytes

Vor den Use-Cases eine Ruby-spezifische Tatsache, die alles prägt: Ein Ruby-String ist eine Folge von Bytes mit einem Kodierungs-Label, und die Encoder sehen sich nur die Bytes an. Das Label sagt Ruby, wie den String anzuzeigen und zu vergleichen ist; es ändert nicht, was kodiert wird:

require "base64"
s = "h\u{e9}llo"
puts s.encoding
# => UTF-8
puts s.bytes.length
# => 6   das betonte e ist zwei Bytes
Base64.strict_encode64(s)
# => "aMOpbGxv"

Das ist die Falle hinter "Warum ist meine Ausgabe länger als erwartet": Der String, den Sie getippt haben, ist in Zeichen gezählt meist kürzer als in Bytes, und Base64 berechnet pro Byte. Die umgekehrte Richtung ist genauso still - ein ungültiger UTF-8-String wird ohne jedes Murren kodiert, denn der Encoder hat nichts zu validieren:

broken = "h\u{e9}llo".b.force_encoding("UTF-8")
broken.setbyte(1, 0xFF)
puts broken.valid_encoding?
# => false
Base64.strict_encode64(broken)
# => irgendein base64, kein Fehler, Bytes sind Bytes

Für echtes Binär überspringen Sie die Text-Maschinerie komplett und bauen Bytes mit pack oder lesen sie mit File.binread ein. Ein befriedigendes Beispiel ist die PNG-Signatur - die acht Bytes, mit denen jede PNG-Datei auf der Erde beginnt:

png_magic = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A].pack("C*")
Base64.strict_encode64(png_magic)
# => "iVBORw0KGgo="

JWTs: Daten signieren, die auch lesbar sind

JSON Web Tokens sind der prominenteste Verbraucher von Rubys URL-sicherem Encoder. Ein Token ist drei base64url-Segmente, durch Punkte verbunden - Header, Payload, Signatur - und die Spezifikation ist eindeutig: Das Alphabet muss das URL-sichere sein, und das Padding muss aus sein. Das jwt-Gem kümmert sich um alles:

# Gemfile: gem "jwt"
require "jwt"
token = JWT.encode(
  { sub: "1234567890", name: "Alice", exp: Time.now.to_i + 3600 },
  "my-secret-key",
  "HS256"
)
puts token
# => eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIi...
payload, header = JWT.decode(token, "my-secret-key", true, algorithm: "HS256")
puts header
# => {"alg"=>"HS256"}

Sie können auch der Base64-Ebene dabei zusehen, wie sie im Token ihren Job macht, denn die Segmente sind einfach base64url von JSON:

require "base64"
require "json"
payload_json = JSON.generate({ "sub" => "1234567890", "name" => "Alice" })
segment = Base64.urlsafe_encode64(payload_json, padding: false)
puts segment
# => eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIn0

Zwei Regeln gehören zu diesem Use-Case. Bauen Sie in Produktion niemals ein JWT von Hand - die Signatur ist das, was ein Token zu mehr macht als ein Schuldeingeständnis - und wenn Sie mit dem Gem dekodieren, fixieren Sie den Algorithmus im Options-Hash wie oben gezeigt, damit der Header des Tokens selbst die Verifizierungsmethode nicht für Sie wählen kann.

HTTP Basic Auth: Den Header bauen

Der älteste Weg, in HTTP zu sagen "Wer bin ich?", ist immer noch der einfachste: Kodieren Sie die Anmeldedaten in Base64, stellen Sie sie nach dem Wort Basic und senden Sie den Header. In Ruby zu bauen ist eine Zeile:

require "base64"
credentials = Base64.strict_encode64("alice:s3cr3t!")
puts "Basic #{credentials}"
# => Basic YWxpY2U6czNjcjN0IQ==

Rubys Standard-Bibliothek macht genau das für Sie in Net::HTTP und ruft das Kern-pack-Template direkt auf - ["user:pass"].pack("m0") ist das, worauf sich basic_auth unter der Haube reduziert:

require "net/http"
request = Net::HTTP::Get.new("https://example.org/api")
request.basic_auth("alice", "s3cr3t!")
puts request["Authorization"]
# => Basic YWxpY2U6czNjcjN0IQ==

Und der Sicherheits-Hinweis, einmal ausgesprochen, damit er in den Akten steht: Base64 ist ein Übersetzer, kein Schloss. Die Anmeldedaten in einem Basic-Auth-Header sind für jeden lesbar, der das Paket lesen kann. Dieser Header ist nur über HTTPS akzeptabel, wo die Übertragung den eigentlichen Schutz erledigt.

Data-URIs: Inline-Bilder und Schriften

Eine Data-URI ist die Antwort des Webs auf "Ich will dieses Bild ohne separate Datei": ein Medientyp, das Wort base64, ein Komma und die Bytes. So liefern Single-File-HTML-Demos ihre Logos aus, so verstecken sich Favicons im CSS, und so kann ein generiertes Bild komplett in einem Template-String leben:

require "base64"
png = File.binread("logo.png")
data_uri = "data:image/png;base64,#{Base64.strict_encode64(png)}"
css = "background-image: url(#{data_uri});"
puts css.length
# => Ihr Stylesheet, minus eine HTTP-Anfrage

Verwenden Sie hier strict_encode64 - der Payload ist eine einzige saubere Zeile, kein Umbruch, kein Newline. Und achten Sie auf die Größe: Das Bild, das Sie inline einbetten, wächst um etwa ein Drittel, also glänzen Data-URIs bei kleinen Assets (Favicons, Logos, Icon-Schriften) und blähen bei großen auf. Ein Zwei-Megabyte-Hero-Foto wird zu 2,7 Megabyte Ihres HTML-Dokuments, und Ihre Nutzer werden es beim ersten 4G-Scroll spüren.

E-Mail: Woher Base64 stammt

Jeder andere Use-Case in diesem Artikel ist ein Nachkomme dieses einen. SMTP wurde in den 1980er-Jahren für kurze Zeilen aus 7-Bit-Text entworfen, was so viel heißt wie: Es konnte kein JPEG transportieren. Die Lösung - Privacy-Enhanced Mail, dann MIME im Jahr 1993 - bestand darin, Binärdaten als Text mit einem 64-Zeichen-Alphabet umzuschreiben, genau das Format, das Sie heute verwenden. Die Narben sind in Rubys Ausgabe immer noch zu sehen: encode64 bricht bei 60 Zeichen um - eine Breite, die keinem bestimmten Protokoll dient, wie Sie später sehen werden, aber kurz genug, um E-Mails höflich zu halten.

In der Praxis werden Sie das mail-Gem die MIME-Arbeit erledigen lassen. Hängen Sie eine Binärdatei an, und das Gem wählt den Base64-Encoder, bricht die Zeilen um und schreibt die Header:

# Gemfile: gem "mail"
require "mail"
message = Mail.new do |m|
  m.from = "dev@example.org"
  m.to = "ops@example.org"
  m.subject = "Binary report"
  m.add_file("report.bin")
end
puts message.encoded
# der Anhang-Teil trägt Content-Transfer-Encoding: base64

Nicht-ASCII-Text in Headern bekommt dieselbe Behandlung in einem etwas anderen Kostüm: RFC-2047-encoded words, die Base64 in einem Charset-Tag zwischen Fragezeichen verpacken, zum Beispiel =?UTF-8?B?w7wgc2VjcmV0cw==?=. Wenn Sie die je von Hand bauen oder parsen, ist das Base64 darin die gewöhnliche Sorte, dekodiert mit decode64 und dann mit dem Charset neu beschriftet, das das Wort deklariert.

PEM-Rüstung für Schlüssel und Zertifikate

Schlüssel und Zertifikate tragen PEM-Rüstung, und die Rüstung ist Base64 mit Rahmen: eine BEGIN-Zeile, die kodierten Bytes in Zeilen zu 64 Zeichen und eine END-Zeile. Wenn Sie je eine PEM-Datei aus rohen DER-Bytes erzeugen müssen, ist der Aufbau ein zweistufiges Einwickeln:

require "base64"
der_bytes = File.binread("server.der")
body_lines = Base64.strict_encode64(der_bytes).scan(/.{1,64}/)
pem = (["-----BEGIN PRIVATE KEY-----"] + body_lines +
  ["-----END PRIVATE KEY-----"]).join("\n") + "\n"
File.write("server.key", pem)

Zwei Hinweise. Erstens werden Sie das fast nie brauchen, denn das openssl-Gem schreibt PEM für Sie (key.to_pem), und das Label zwischen den BEGIN- und END-Zeilen muss mit dem Inhalt übereinstimmen - falsch gemacht, entsteht eine Datei, die jedes Tool im Internet ablehnt. Zweitens ist die Zeilenlänge hier 64, die klassische PEM-Breite; Rubys encode64 bricht stattdessen bei 60 um, und jeder anständige PEM-Parser ignoriert Zeilängen komplett, also dekodiert jede der beiden Breiten ohne Weiteres.

Dateien: Die .b64-Konvention

Das häufigste Dateiformat in der Base64-Welt ist eine einfache Textdatei mit der Endung .b64 (oder .base64), die einen kodierten Payload enthält - denken Sie daran als "die Datei, aber sicher an jeder Stelle einfügbar". Eine davon aus Ruby zu erzeugen ist ein One-Liner:

require "base64"
File.write("payload.b64", Base64.strict_encode64(File.binread("payload.bin")))
puts File.size("payload.b64")
# => ungefähr das 1,33-Fache der Originalgröße

Verwenden Sie strict_encode64, damit die Datei eine einzige saubere Zeile enthält - die Konvention, die die meisten Dekodier-Tools (und Rubys strenger Dekodierer) erwarten. Zurücklesen ist das Spiegelbild: einlesen, dekodieren und die Bytes im Binärmodus schreiben, damit sich auf dem Weg nach draußen nichts daran verändert:

encoded = File.read("payload.b64")
bytes = Base64.strict_decode64(encoded)
File.binwrite("restored.bin", bytes)

Wenn Ihre .b64-Dateien von Tools kommen, die Zeilen umbrechen - manche base64-CLI-Varianten tun das - streichen Sie die Zeilenumbrüche vor einem strengen Dekodieren, oder verwenden Sie den nachsichtigen Dekodierer, der sie gratis überspringt.

Konfigurationsdateien, Umgebungsvariablen und Datenbanken

Wann immer binäre Daten in einem Textdokument leben müssen, ist Base64 die Brücke. Das Muster wiederholt sich an drei Orten mit kleinen Variationen.

Umgebungsvariablen und .env-Dateien können keine rohen Bytes halten, also werden die Bytes kodiert, bevor sie die Maschine verlassen, die sie hat:

require "base64"
# irgendwo, wo Sie die App provisionieren
ENV["APP_LOGO"] = Base64.strict_encode64(File.binread("logo.png"))
# irgendwo, wo die App startet
b64 = ENV.fetch("APP_LOGO")
File.binwrite("logo.png", Base64.decode64(b64))

YAML hat einen nativen Binärtyp, und Psych erledigt das Base64 für Sie - ein BINARY-String, der nach YAML gedumpt wird, kommt als !binary-Skalar heraus, und wird byte-identisch zurückgeladen:

require "yaml"
yaml_text = YAML.dump({ "logo" => File.binread("logo.png") })
puts yaml_text.lines.first(2)
# => "---"
# => "logo: !binary |-"
data = YAML.load(yaml_text)
puts data["logo"].encoding
# => ASCII-8BIT

In Datenbanken ist die Frage der Speichertyp, nicht das Encoding. Wenn Ihre Datenbank eine echte Binärspalte hat - BLOB, BYTEA, VARBINARY - nutzen Sie sie und lassen Sie den Treiber die Bytes tragen. Base64 in einer TEXT-Spalte ist das Muster für den Fall, dass die Speicherungsschicht nur Strings spricht: manche Dokumenten-Stores, JSON-artige APIs oder ein Legacy-Schema, das Sie nicht ändern können. Der Preis ist die Ein-Drittel-Größensteuer auf der Spalte und die Disziplin, beim Hineingehen zu kodieren und beim Rausgehen an jeder Grenze zu dekodieren, ohne Ausnahme.

Prüfsummen, die als Text reisen

Hashes sind binär, aber Prüfsummen reisen meist im Text: Datei-Integritätslisten, Cache-Keys, Fingerabdrücke, Log-Zeilen. Rubys Digest-Klassen haben jeweils eine base64digest-Methode, die das Kodieren in einem einzigen Aufruf erledigt:

require "digest"
Digest::SHA256.base64digest("hello")
# => "LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ="

Die Ausgabe ist gepaddetes Standard-Base64 - dasselbe, was Sie aus Base64.strict_encode64(Digest::SHA256.digest("hello")) bekommen würden - also sicher zu speichern, zu vergleichen und einzufügen. Die einzige Entscheidung ist Konsistenz: Eine mit Base64 erzeugte Prüfsummenliste muss gegen Base64-Ausgabe geprüft werden, und Hex- und Base64-Darstellungen desselben Hashes sind unterschiedliche Strings - wählen Sie also einen und bleiben Sie dabei.

Große Dinge in kleinen Chunks kodieren

Wie die Dekodierer sind die Encoder pufferbasiert: Sie lesen die gesamte Eingabe ein und geben die gesamte Ausgabe aus. Es gibt keinen Streaming-Encoder in der Standard-Bibliothek, also lautet der Plan für große Payloads: Speicher - und die Mathematik hat eine angenehme Symmetrie. Kodieren vergrößert Ihre Daten um ein Drittel, also ist die Ausgabe - nicht die Eingabe - Ihre größte Allokierung, und für eine 1-Gigabyte-Datei sollten Sie mit rund 1,33 Gigabyte Text vor sich rechnen.

Wenn das zu viel zum einmaligen Halten ist, können Sie in Chunks kodieren, denn das Base64-Alphabet ist an drei-Byte-Grenzen selbst-synchronisierend: Kodieren Sie jede 3-Byte-Scheibe unabhängig, und die Verkettung ist identisch mit dem Kodieren des Ganzen:

require "base64"
require "securerandom"
bin = SecureRandom.random_bytes(10_001)
whole = Base64.strict_encode64(bin)
chunked = bin.scan(/.{1,3}/m).map { |slice| Base64.strict_encode64(slice) }.join
puts chunked == whole
# => true

Derselbe Trick gibt Ihnen einen selbstgebastelten Zeilen-Umbruch, der encode64 exakt entspricht: 45 Bytes kodieren immer zu exakt 60 Zeichen, also liefert das Aufschneiden der Eingabe auf 45 Bytes und das Verbinden der Teile mit Zeilenumbrüchen die klassische MIME-Ausgabe, Zeile für Zeile, mit nur einer Scheibe im Speicher auf einen Schlag:

def wrap_like_encode64(bin)
  lines = bin.scan(/.{1,45}/m).map { |slice| Base64.strict_encode64(slice) }
  lines.join("\n") + "\n"
end
bin = SecureRandom.random_bytes(10_001)
puts wrap_like_encode64(bin) == Base64.encode64(bin)
# => true

Von der Kommandozeile

Auch zum Kodieren brauchen Sie keine Skript-Datei. Die One-Liner-Form liest eine Datei ein und schreibt ihr Base64 nach stdout:

ruby -rbase64 -e 'print Base64.strict_encode64(File.binread(ARGV[0]))' payload.bin > payload.b64

Und die Pipe-Form liest stdin, so wickeln Sie einen Byte-Stream von einem beliebigen anderen Befehl ein:

some_command | ruby -rbase64 -e 'print Base64.strict_encode64(STDIN.read)'

Behalten Sie in beiden print bei - ein versehentliches puts würde ein Newline an Ihr Base64 hängen, und bei strict_encode64-Ausgabe macht das aus einem sauberen Token ein kaputtes. Die Daumenregel ist dieselbe wie auf der Dekodier-Seite: Wenn der nächste Verbraucher Ihrer Ausgabe streng ist, darf nichts außer dem Base64 selbst mitreisen.

Die Fallen, die Ruby-Entwicklern extra Bytes kosten

  • Das anhängende Newline in JSON. Base64.encode64 beendet jedes nicht-leere Ergebnis mit einem Zeilenumbruch, also kommt ein Wert, der ein sauberes Token sein sollte, in Ihrem JSON mit einem Überraschungs-\n am Ende an. Verwenden Sie strict_encode64 für alles, was gespeichert, verglichen oder in einer einzigen Zeile gesendet wird.
  • Der 60-Zeichen-Umbruch in Tokens und URLs. Dieselbe Methode bricht lange Ausgabe in mehrere Zeilen um. Ein umgebrochener String in einer URL sind zwei URLs, und ein umgebrochenes Token ist ein kaputtes. Wieder: strict_encode64 - oder strip/delete für die Zeilenumbrüche, wenn Sie an encode64-Ausgabe feststecken.
  • Plus und Schrägstrich in URLs. Standard-Base64 in einem Query-String heißt, %2B, %2F und %3D auf dem Weg nach draußen zu percent-kodieren und darauf zu hoffen, dass die andere Seite sie dekodiert. urlsafe_encode64 entfernt das Problem an der Quelle.
  • Padding am falschen Ort. JWTs und andere Token-Schemata wollen Padding aus; MIME-Leser kommen mit fehlendem Padding womöglich nicht zurecht. Erzeugen Sie padding: false nur dort, wo eine Spezifikation es verlangt, und wissen Sie, auf welcher Seite des Zauns jeder Ihrer Verbraucher sitzt.
  • Zeichen sind keine Bytes. Ein fünfzeichenlanger String mit einem Betonungsbuchstaben ist in UTF-8 sechs Bytes, und die Längen-Mathematik der Ausgabe läuft auf Bytes. Wenn das kodierte Ergebnis "zu lang" ist, zählen Sie Bytes, keine Zeichen.
  • Die Ein-Drittel-Steuer im Schema-Design. Ein 16-kB-BLOB wird zu einem rund 22-kB-Base64-String in einer TEXT-Spalte. Dimensionieren Sie Ihre Spalten, Caches und API-Payloads für die kodierte Form, nicht für die binäre Form.
  • Zwei Alphabete, zwei verschiedene Strings. Dieselben Bytes kodieren sich im Standard- und im URL-sicheren Alphabet unterschiedlich, also ist ein kodierter Wert nur mit einem anderen Wert aus demselben Alphabet vergleichbar. Vergleichen oder vermischen Sie sie niemals.
  • Base64 ist kein Schloss. Ein Geheimnis zu kodieren macht es nicht geheim. Jeder mit dem String hat Ihre Daten; Base64 steuert nur, wie die Bytes aussehen, nicht, wer sie lesen kann.

Gewohnheiten, die Bytes und Bugs sparen

  • Machen Sie strict_encode64 zu Ihrem Standard. Wechseln Sie zu urlsafe_encode64, in dem Moment, in dem die Ausgabe in einer URL, einem Cookie oder einem Identifier leben wird, und zu encode64 nur, wenn das Ziel ein zeilenorientiertes Textprotokoll wie E-Mail ist.
  • Halten Sie das Alphabet zwischen Encoder und Decoder an beiden Enden der Leitung konsistent. Der häufigste "Base64 kaputt"-Bug ist ein Erzeuger mit Standard-Alphabet, der auf einen URL-sicheren Verbraucher trifft, oder umgekehrt.
  • Füttern Sie die Encoder mit Bytes, die Sie wirklich kodieren wollen: File.binread für Dateien, pack für konstruiertes Binär und einen UTF-8-String, wenn der String die Daten ist. Der Encoder wird Ihre Wahl nicht infrage stellen - er zählt nur Bytes.
  • Haushalten Sie mit dem Wachstum. Wann immer ein Base64-String eine Grenze in einen begrenzten Container überquert, multiplizieren Sie mit 4/3 und rechnen Sie etwas Puffer für das Padding ein.
  • Verwenden Sie Base64 für Transportierbarkeit, niemals für Geheimhaltung. Wenn das Ziel ist, die Daten privat zu halten, ist das Werkzeug die Verschlüsselung, und Base64 ist nur das, was Sie danach mit dem Chiffretext machen.

Wie Base64 zu einem Gem wurde

Den größten Teil seines Lebens war das Base64-Modul einfach eine Datei in der Standard-Bibliothek, so wie viele der ältesten Helfer von Ruby. Die strict- und URL-sicheren Methoden kamen zum ursprünglichen Paar während der 1.9-Entwicklungslinie - die gesamte base64-Bibliothek mit allen vier Methoden kam im September 2008 in den trunk und wurde erstmals in 1.9.1 (2009) ausgeliefert - und das padding:-Keyword kam 2015 mit Ruby 2.3. Alles an der API, die Sie heute sehen, hatte sich bis dahin eingespielt - der Rest der Geschichte handelt davon, wie das Modul ausgeliefert wird.

2020, mit Ruby 3.0, begann das Core-Team, Standard-Bibliotheken in eigene Gems auszulagern, und base64 wurde eines davon: Version 0.1.0, gepflegt im ruby/base64-Repository von den Core-Beitragenden. Es wurde als default gem ausgeliefert - verteilt mit Ruby und immer verfügbar, also blieb require "base64" ohne jeden Zeremonienlauf funktionieren. Version 0.2.0 folgte 2023 mit Ruby 3.3 und fügte die Base64::VERSION-Konstante und ein deutlich reichhaltigeres Dokumentationspaket hinzu.

Dann zeichnete Ruby 3.4 im Dezember 2024 die Linie neu: base64 wanderte von der Default-Gem-Liste auf die bundled gem-Liste, dasselbe Regal wie csv und drb. Bundled Gems werden weiterhin mit der Sprache ausgeliefert, aber Bundler-basierte Projekte sollen sie deklarieren - also fügen Sie Ihrem Gemfile gem "base64" hinzu (oder führen Sie gem install base64 aus), wenn Sie auf Ruby 3.4 oder neuer sind und Ihre App von Bundler gesteuert wird, und Sie sind abgedeckt. Ruby 4.0 im Jahr 2025 brachte Version 0.3.0 mit RBS-Typsignaturen, damit statische Checker das Modul ordentlich sehen können.

Auf der ganzen Reise blieb die Implementierung, was sie immer war: ein paar Dutzend Zeilen reines Ruby um die Kern-Templates pack und unpack gewickelt. Keine C-Erweiterung, keine Abhängigkeiten und - mit einer Downloadzahl im Hundert-Millionen-Bereich auf rubygems.org - eines der meist installierten Gems der Plattform.

Schöne Ruby-Fakten

  • Das gesamte Modul, Encoder eingeschlossen, ist kurz genug, um es in einer einzigen Kaffeepause zu lesen. encode64 ist buchstäblich [bin].pack("m"), strict_encode64 ist [bin].pack("m0"), und urlsafe_encode64 ist der strenge Encoder mit einem Zwei-Buchstaben-Tausch obendrauf, minus Padding, wenn Sie es fragen.
  • Der 60-Zeichen-Umbruch von encode64 passt weder zu MIMEs 76-Zeichen-Maximum noch zu PEMs klassischem 64. Es ist einfach das, was das m-pack-Template immer getan hat, und der Base64-Encoder des mail-Gems kommentiert es beifallstollend: Rubys automatischer Zeilenumbruch hält die Ausgabe innerhalb der SMTP-Grenzen.
  • Rubys Net::HTTP lässt sich nicht auf das Base64-Modul für Basic Auth ein - es ruft das pack-Template direkt auf, was eine schöne Erinnerung daran ist, dass das Modul eine Komfortschicht über dem Kern ist, nicht umgekehrt.
  • Jede Digest-Klasse trägt eine base64digest-Methode, also ist Digest::SHA256.base64digest ein Bürger erster Klasse neben hexdigest - Prüfsummen im Text ohne zweiten Aufruf.
  • YAMLs !binary-Tag ist Base64 im Verkleidungskostüm. Psych erledigt die Kodierung in dem Moment, in dem Sie einen BINARY-String dumpen - und deshalb sehen Konfigurationsdateien voller Binärs so aus, wie sie aussehen.
  • Das Modul, das Sie verwenden, war nicht immer das Modul, das Sie sich erinnern. Altes Ruby hatte b64encode (Umbruch bei einer gewählten Breite) und decode_b (RFC-2047-Header-Dekodierung); beide verschwanden in der 1.9-Linie, also stirbt jeder vor-2010-Code, den Sie erben und der sie aufruft, mit einem NoMethodError.
  • Youtubes Video-IDs sind base64url ohne Padding - elf Zeichen, kein Plus, kein Schrägstrich, kein Gleichheitszeichen - genau die Art kurzer, link-sicherer Identifier, für die das URL-sichere Alphabet entworfen wurde.

Die andere Seite

Sie haben jetzt das komplette Encoding-Bild: ein Standard-Workhorse, das Sie nie überrascht, einen Klassiker, der für die Protokolle, die es verlangen, Zeilen umbrechen, ein link-sicheres Alphabet mit einem Padding-Schalter und die Byte-Ebene-Regeln, die exakt entscheiden, wie Ihre Ausgabe aussehen wird. Die umgekehrte Richtung - einen Base64-String zerlegen, zwischen den drei Dekodierern von Ruby wählen und die resultierenden Bytes in etwas verwandeln, das Sie verwenden können - hat ihre eigenen stillen Fallen, angefangen bei einem Dekodierer, der nie Nein sagt. Die andere Straßenseite wird ausführlich im Base64-Dekodierungs-Artikel behandelt, verlinkt unten.

Zuletzt aktualisiert: 2026-09-08

Verwandter Artikel: Base64-Dekodierung in Ruby: Ein vollständiger Leitfaden