2012-01-28 20 views
6

Przy wdrażaniu usług HTTP w node.js, istnieje wiele przykładowy kod jak poniżej używany do dostać całą jednostkę życzenie (dane przesłane przez klienta, na przykład stanowisko z danymi JSON):Problemy z parsowaniem znaków UTF8 w treści żądania?

var http = require('http'); 

var server = http.createServer(function(req, res) { 
    var data = ''; 
    req.setEncoding('utf8'); 

    req.on('data', function(chunk) { 
     data += chunk; 
    }); 

    req.on('end', function() { 
     // parse data 
    }); 
}); 

Korzystanie z req.setEncoding('utf8') powoduje automatyczne dekodowanie bajtów wejściowych na łańcuch, przy założeniu, że dane wejściowe są zakodowane w UTF8. Ale mam wrażenie, że może się zepsuć. Co stanie się, jeśli otrzymamy fragment danych kończący się w środku wielobajtowej postaci UTF8? Możemy symulować to:

> new Buffer("café") 
<Buffer 63 61 66 c3 a9> 
> new Buffer("café").slice(0,4) 
<Buffer 63 61 66 c3> 
> new Buffer("café").slice(0,4).toString('utf8') 
'caf?' 

Więc otrzymujemy błędne charakter zamiast czekać na kolejne bajty poprawnie zdekodować ostatni znak.

Dlatego, o ile obiekt żądania nie dba o to, upewniając się, że tylko całkowicie zdekodowane znaki są wciskane w porcje, ta wszechobecna próbka kodu jest zepsuta.

Alternatywą byłoby użycie buforów, obchodzenia się z problemem limitów rozmiar bufora:

var http = require('http'); 
var MAX_REQUEST_BODY_SIZE = 16 * 1024 * 1024; 

var server = http.createServer(function(req, res) { 
    // A better way to do this could be to start with a small buffer 
    // and grow it geometrically until the limit is reached. 
    var requestBody = new Buffer(MAX_REQUEST_BODY_SIZE); 
    var requestBodyLength = 0; 

    req.on('data', function(chunk) { 
     if(requestBodyLength + chunk.length >= MAX_REQUEST_BODY_SIZE) { 
      res.statusCode = 413; // Request Entity Too Large 
      return; 
     } 
     chunk.copy(requestBody, requestBodyLength, 0, chunk.length); 
     requestBodyLength += chunk.length; 
    }); 

    req.on('end', function() { 
     if(res.statusCode == 413) { 
      // handle 413 error 
      return; 
     } 

     requestBody = requestBody.toString('utf8', 0, requestBodyLength); 
     // process requestBody as string 
    }); 
}); 

mam rację, czy też jest to już załatwione przez klasę żądanie HTTP?

+0

Dziękuję za pytanie. Myślałem, że oszalałem jako jedyna osoba na świecie, która myślała, że ​​to może być problem ;-) – dty

Odpowiedz

7

Zostaje to uwzględnione automatycznie. W węźle znajduje się moduł string_decoder, który jest ładowany po wywołaniu funkcji setEncoding. Dekoder sprawdzi ostatnie kilka otrzymanych bajtów i zapisze je między emisjami "danych", jeśli nie są pełnymi znakami, więc dane zawsze będą miały prawidłowy ciąg znaków. Jeśli nie ustawisz setEncoding i nie użyjesz samego string_decoder, to bufor emitowany może mieć problem, o którym wspomniałeś.

Docs nie są zbyt pomocne choć http://nodejs.org/docs/latest/api/string_decoder.html, ale widać moduł tutaj, https://github.com/joyent/node/blob/master/lib/string_decoder.js

wdrożenie „setEncoding” i logiki do emitowania również czyni go bardziej zrozumiałym.

1

Wystarczy dodać response.setEncoding ('utf8'); do wywołania zwrotnego request.on ('response'). W moim przypadku było to wystarczające.

0
// Post : 'tèéïst3 ùél' 
// Node return : 't%C3%A8%C3%A9%C3%AFst3+%C3%B9%C3%A9l' 
decodeURI('t%C3%A8%C3%A9%C3%AFst3+%C3%B9%C3%A9l'); 
// Return 'tèéïst3+ùél' 
Powiązane problemy