2012-01-28 8 views
6

Al implementar servicios HTTP en Node.js, hay una gran cantidad de código de ejemplo, como a continuación se utiliza para obtener toda la entidad de solicitud (datos cargados por el cliente, por ejemplo un post con los datos JSON):Problemas con el análisis de caracteres UTF8 en el cuerpo de la solicitud?

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 
    }); 
}); 

El uso de req.setEncoding('utf8') decodifica automáticamente los bytes de entrada en cadena, suponiendo que la entrada está codificada en UTF8. Pero tengo la sensación de que se puede romper. ¿Qué pasa si recibimos un fragmento de datos que termina en medio de un carácter UTF8 de múltiples bytes? Podemos simular este:

> 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?' 

por lo que tenemos un carácter errónea lugar de esperar a los próximos bytes para decodificar correctamente el último carácter.

Por lo tanto, a menos que el objeto de solicitud tenga cuidado de esto, asegurándose de que solo los caracteres decodificados por completo se inserten en fragmentos, esta muestra de código omnipresente se rompe.

La alternativa sería utilizar tampones, manejar el problema de límites de tamaño de búfer:

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 
    }); 
}); 

Estoy en lo cierto, o es ya atendidos por la clase de petición HTTP?

+0

Gracias por preguntar esto. Pensé que me estaba volviendo loco ser la única persona en el planeta que pensó que esto podría ser un problema ;-) – dty

Respuesta

7

Esto se soluciona automáticamente. Hay un módulo string_decoder en el nodo que se carga cuando llamas a setEncoding. El decodificador verificará los últimos bytes recibidos y los almacenará entre los emitidos de "datos" si no son caracteres completos, por lo que los datos siempre obtendrán una cadena correcta. Si no hace setEncoding, y no usa string_decoder usted mismo, entonces el búfer emitido puede tener el problema que usted mencionó.

Los documentos que no son de mucha ayuda, sin embargo, http://nodejs.org/docs/latest/api/string_decoder.html, pero se puede ver el módulo aquí, https://github.com/joyent/node/blob/master/lib/string_decoder.js

La aplicación de 'setEncoding' y la lógica para emitir también hace que sea más clara.

1

Sólo tiene que añadir response.setEncoding ('UTF-8'); para request.on ('respuesta') función de devolución de llamada. En mi caso eso fue suficiente.

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' 
Cuestiones relacionadas