base64 encoding von Dateien in Node.js

Es gibt ja tatsächlich noch Webservices, die SOAP Requests erwarten und so musste ich vor kurzem einen solchen Service ansprechen. Nicht nur das, der Endpoint erwartete auch noch ein File, base64 encoded. Soweit wäre das alles ja noch kein Problem, man bekommt ein File via Upload in FormData, via busboy erhält man das File als Stream und der Spaß kann losgehen. In diesem Projekt handelte es sich jedoch um eine größere Lösung aus verschiedenen Microservices und der Upload des Files wird von einer Art Zwischen-API durchgeführt, da der Endpoint ziemlich hässlich ist und wir unsere richtige API nicht versauen wollten. Deshalb geht alle Kommunikation zu diesem speziellen Endpoint über eine dedizierte Mini-API, allerdings erhält die Mini-API somit das File aber als file im body der Route.

Stopf es einfach in einen Buffer

War zumindest mein initialer Gedanke, also gesagt, getan.

router.post('/', function (req, res, next) {

  const file = req.body
  const b64String = new Buffer(file).toString('base64')
  // auch probiert:
  // const b64String = new Buffer(file, 'base64')

  // ... hier kam die weitere Erstellung des SOAP Requests und dann der http request
})

Error! Das würde soweit funktionieren, wenn es sich um einen Stream, einen Buffer oder einen String handeln würde, aber ein File konnte ich nicht in den Buffer stecken. Ich dachte bisher tatsächlich, ich könnte alles buffern, hatte immer geklappt, aber base64 encoding von Dateien schien nicht trivial. Was macht ein guter Dev also? Stackoverflow’n! Der Arbeitstag neigte sich schon langsam den Ende, es kann also gut sein, dass meine Google-Fähigkeiten mittlerweile eher bescheiden waren, aber irgendwie hab ich nichts gefunden. Natürlich gab es online Einiges zu Uploads aus dem Frontend, aber hier war es ein simpler API-zu-API-Transfer.

Reif für den Feierabend und mit wirren Gedanken führte sogar so weit, dass ich in Betracht zog, das File temporär über das FileSystem auf die Platte zu schreiben und dann via ReadStream wieder einzulesen. Aber das war Code, nach dem ich mich dann duschen wollte. Das konnte einfach nicht richtig sein. Es musste einfach noch eine andere Möglichkeit geben, base64 encoding von Dateien durchzuführen.

base64 encoding von Dateien – diesmal richtig

Die Lösung war dann doch einfacher, als erwartet. stream.Writable() zur Rettung!

Da in der Mini-API kein andere body empfangen wird, hab ich in der app.js den bodyParser auf raw gesetzt, sodass alle bodies direkt als Buffer geparsed werden.

app.use(bodyParser.raw({ bytes: config.bodyparserRawLength }))

Danach musste nur noch der writable stream instanziiert und der body auf den stream gepiped werden.

router.post('/', function (req, res, next) {

  const converter = new stream.Writable()

  converter.data = []
  converter.write = function (chunk) {
    this.data.push(chunk)
  }
  converter.on('finish', function () {
    const b = Buffer.concat(this.data)
    const b64 = b.toString('base64')

    // Hier kann der base64 String weiter verarbeitet werden
  })

  req.pipe(converter)
})

Der request kann hier direkt auf den converter gepiped werden, da nur der body des requests – in diesem Fall das File – gepiped wird. Der dann enthaltene Datensatz der Chunks wird via Buffer.concat() konkateniert und zu base64 konvertiert. Fertig ist das base64 encoding von Dateien und der wundervolle SOAP Request konnte durchgeführt werden 👍

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.