2010-09-14 8 views
15

Korzystanie z węzła v0.2.0 Próbuję pobrać obraz z serwera, przekonwertować go na ciąg base64, a następnie osadzić go na stronie w tagu obrazu. Mam następujący kod:Node.js base64 kodują pobrany obraz do użycia w URI danych

var express = require('express'), 
request = require('request'), 
sys = require('sys'); 

var app = express.createServer(
    express.logger(), 
    express.bodyDecoder() 
); 

app.get('/', function(req, res){ 

    if(req.param("url")) { 
     var url = unescape(req.param("url")); 
     request({uri:url}, function (error, response, body) { 
      if (!error && response.statusCode == 200) { 

       var data_uri_prefix = "data:" + response.headers["content-type"] + ";base64,"; 
       var buf = new Buffer(body); 
       var image = buf.toString('base64'); 

       image = data_uri_prefix + image; 

       res.send('<img src="'+image+'"/>'); 

      } 
     }); 
    } 
}); 

app.listen(3000); 

Uwaga: Ten kod wymaga "express" i "request". I oczywiście, node. Jeśli masz zainstalowany npm, powinno być tak proste, jak "npm install express" lub "npm install request".

Niestety to nie działa zgodnie z oczekiwaniami. Jeśli zrobić konwersję z Google logo, a następnie pojawia się następujący na początku łańcucha:

77 + 9UE5HDQoaCgAAAA1JSERSAAABEwAAAF8IAwAAAO +/ve +/ve +/vSkAAAMAUExURQBzCw5xGiNmK0t + U ++/vQUf77 + 9BiHvv70WKO +/vQkk77 + 9D

Jednak jeśli używam online Base64 encoder z tym samym obrazem, to działa idealnie. Łańcuch zaczyna się tak:

iVBORw0KGgoAAAANSUhEUgAAARMAAABfCAMAAAD8mtMpAAADAFBMVEUAcwsOcRojZitLflOWBR + aBiGQFiipCSS8DCm1Cya1FiyNKzexKTjDDSrLDS

Gdzie ja mam źle, że to nie działa poprawnie? Próbowałem wielu różnych implementacji js base64 i wszystkie nie działają w ten sam sposób. Jedyne co mogę myśleć to to, że próbuję przekonwertować niewłaściwą rzecz na base64, ale co powinienem przekonwertować, jeśli tak jest?

Odpowiedz

13

Problem polega na kodowaniu i zapisywaniu danych binarnych w łańcuchach javascript. W sekcji Bufory znajduje się całkiem niezła sekcja pod adresem http://nodejs.org/api.html.

Niestety, najprostszym sposobem rozwiązania tego problemu była zmiana żądania npm. Musiałem dodać response.setEncoding('binary'); w linii 66 tuż ​​poniżej var buffer; w /path/to/lib/node/.npm/request/active/package/lib/main.js. To zadziała dobrze dla tego żądania, ale nie dla innych. Możesz zhakować go tak, aby był ustawiony tylko na podstawie innej, przekazanej opcji.

Potem zmieniono var buf = new Buffer(body) na var buf = new Buffer(body, 'binary');. Po tym wszystko działało dobrze.

Innym sposobem, aby to zrobić, jeśli naprawdę nie chcesz dotknąć żądania npm, byłoby przekazanie obiektu, który implementuje zapisywalny strumień w argumencie responseBodyStream, aby zażądać. Obiekt ten będzie następnie przechowywać strumień danych z odpowiedzi w swoim własnym buforze. Może jest biblioteka, która robi to już ... nie jestem pewien.

Zostawię to tutaj na razie, ale nie krępuj się komentować, jeśli chcesz, żebym coś wyjaśnił.

EDIT

odjazdu komentarze.Nowe rozwiązanie w http://gist.github.com/583836

+0

Dzięki, to działa, ale nie podoba mi się pomysł edycji pakietu żądania, aby działał. Jak dokładnie zaimplementujesz obiekt typu Zapisywalny strumień? Nie mogę wymyślić, jak go stworzyć. Każda pomoc będzie naprawdę doceniona! – betamax

+0

Znaleziono ładną wersję do zapisu na stronie http://github.com/substack/node-bufferlist. Oto zaktualizowana wersja kodu, która nie musi modyfikować biblioteki żądań: http://gist.github.com/583836. – bxjx

+0

, które działają dla Ciebie? – bxjx

8

Następujący kod (dostępny w https://gist.github.com/804225)

var URL = require('url'), 
    sURL = 'http://nodejs.org/logo.png', 
    oURL = URL.parse(sURL), 
    http = require('http'), 
    client = http.createClient(80, oURL.hostname), 
    request = client.request('GET', oURL.pathname, {'host': oURL.hostname}) 
; 

request.end(); 
request.on('response', function (response) 
{ 
    var type = response.headers["content-type"], 
     prefix = "data:" + type + ";base64,", 
     body = ""; 

    response.setEncoding('binary'); 
    response.on('end', function() { 
     var base64 = new Buffer(body, 'binary').toString('base64'), 
      data = prefix + base64; 
     console.log(data); 
    }); 
    response.on('data', function (chunk) { 
     if (response.statusCode == 200) body += chunk; 
    }); 
}); 

powinny również wytwarzać URI danych bez konieczności stosowania jakichkolwiek zewnętrznych modułów.

1

Działa to dla mnie za pomocą żądania:

const url = 'http://host/image.png'; 
request.get({url : url, encoding: null}, (err, res, body) => { 
    if (!err) { 
     const type = res.headers["content-type"]; 
     const prefix = "data:" + type + ";base64,"; 
     const base64 = body.toString('base64'); 
     const dataUri = prefix + base64; 
    } 
}); 

Nie potrzeba żadnych buforów pośrednich. Kluczem jest ustawienie kodowania na wartość null.