Foros del Web » Estrategias Digitales y Negocios Online » Negocios »

AJAX, al descargar binario, los caracteres 127+ se evalúan en 65533

Estas en el tema de AJAX, al descargar binario, los caracteres 127+ se evalúan en 65533 en el foro de Negocios en Foros del Web. Hola :) He escrito un código javascript para descargar un archivo de imagen mediante una petición AJAX (El motivo es un larga historia). Pero cuando ...
  #1 (permalink)  
Antiguo 23/07/2011, 18:47
Avatar de Escain  
Fecha de Ingreso: enero-2007
Mensajes: 21
Antigüedad: 17 años, 10 meses
Puntos: 3
Pregunta AJAX, al descargar binario, los caracteres 127+ se evalúan en 65533

Hola :)

He escrito un código javascript para descargar un archivo de imagen mediante una petición AJAX (El motivo es un larga historia).
Pero cuando recibo la cadena de respuesta, todos los bytes 127-255 son sustituidos por el 65533 unicode, con la obvia perdida de información.

Por ejemplo a partir de la imágen:
Código:
66 77 54 16 0 0 0 0 0 0 54 0 0 0 40 0 0 0 32 
0 0 0 32 0 0 0 1 0 32 0 0 0 0 0 0 0 0 0 19 11 
0 0 19 11 0 0 0 0 0 0 0 0 0 0 255 255 255 0 
255 255 255 0 0 0 0 28 0 0 0 65 0 0 0 37 135 
135 135 0 145 145 144 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0...
..
En la cadena javascript recibida obtengo:
Código:
66 77 54 16 0 0 0 0 0 0 54 0 0 0 40 0 0 0 32 
0 0 0 32 0 0 0 1 0 32 0 0 0 0 0 0 0 0 0 19 11 
0 0 19 11 0 0 0 0 0 0 0 0 0 0 65533 65533 65533 0 
65533 65533 65533 0 0 0 0 28 0 0 0 65 0 0 0 37 65533 
65533 65533 0 65533 65533 65533 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0...
..
No tengo gran idea de cual es el problema, he buscado en muchas páginas pero al ser un error tan específico, no he encontrado nada que me saque de duda.

Aquí el código javascript simplificado:
Código:
		var http = new XMLHttpRequest();
		http.onreadystatechange = callbacksend;
		http.open("post", "http://www.miweb.com/Icon.bmp", true);
		http.setRequestHeader("Accept-Charset", "utf-8");
		http.setRequestHeader("Content-Transfer-Encoding","binary");
		http.send(null);

function callbacksend(){
	if(http.readyState == 4){
		if(http.status == 200){
			// todo ok
			for( var i=0; i < 100; i++){
				document.body.appendChild(document.createTextNode(" " + http.responseText.charCodeAt(i)));
			}			
		}
	}
};
La duda es pues: ¿porque algunos bytes son sustituidos por 65533 en el "responseText" y cómo puedo evitar/solucionar este problema?

Les agradezco a todos los que hayáis tomado el tiempo de leer este post por la atención.

Escain
  #2 (permalink)  
Antiguo 23/07/2011, 20:47
Avatar de zerokilled
Javascripter
 
Fecha de Ingreso: abril-2009
Ubicación: Isla del Encanto, La Borinqueña [+>==]
Mensajes: 8.050
Antigüedad: 15 años, 6 meses
Puntos: 1485
Respuesta: AJAX, al descargar binario, los caracteres 127+ se evalúan en 65533

buenas,
he estado tratando de comprender la situación. lo habia intentado con un documento php que genera los caracteres desde el índice 0 hasta el 255 en iso-8859-1 y utf-8. en ninguno de los casos me sucede lo que señalas. sin embargo, si lo intento con un documento *.txt codificado en iso-8859-1 que contiene los caracteres del rango antes mencionado, me sucede lo que explicas a partir de los valores 128 en adelante. lo que sospecho es que se debe a la forma en que el servidor envia el documento. en mi caso el servidor lo envia en application/octet-stream.

__________________
la maldad es una virtud humana,
y la espiritualidad es la lucha del hombre contra su maldad.
  #3 (permalink)  
Antiguo 23/07/2011, 22:19
Avatar de Escain  
Fecha de Ingreso: enero-2007
Mensajes: 21
Antigüedad: 17 años, 10 meses
Puntos: 3
Respuesta: AJAX, al descargar binario, los caracteres 127+ se evalúan en 65533

He probado generar la "imagen" con una sucesión de carácteres de 0 a 255 y me aparece el mismo problema que con la imagen bmp. No he logrado obtener el resultado correcto tal como comentas.
PHP
Código:
<?PHP
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="image.bmp"');
for( $i=0; $i < 256; $i++) echo( chr( $i));
?>
He probado cambiar de servidor por si resultara ser un bug del mismo, pueden testearlo en http://www.leyendaepica.es/include2.html
Así también tienen un acceso mas fácil a los archivos bases para hacer las pruebas.
Me sale exactamente lo mismo con varios exploradores:
Código:
Size: 306
66 77 50 1 0 0 0 0 0 0 54 0 0 0 40 0 0 0 9 0 0 0 9 0 
0 0 1 0 24 0 0 0 0 0 65533 0 0 0 65533 14 0 0 
65533 14 0 0 0 0 0 0 0 0 0 0 36 36 36 82 82 82 
76 76 76 100 88 100 84 80 84 76 76 76 76 76 76 
82 82 82 36 36 36 0 82 82 82 65533 
65533 65533 65533 65533 65533...
...
Personalmente tiendo a pensar en un problema de javascript puesto que las imágenes se envían correctamente en todos los casos "no ajax", por ejemplo escribiendo directamente Icon.bmp en la barra de direcciones.
  #4 (permalink)  
Antiguo 24/07/2011, 07:27
Avatar de Panino5001
Me alejo de Omelas
 
Fecha de Ingreso: mayo-2004
Ubicación: -34.637167,-58.462984
Mensajes: 5.148
Antigüedad: 20 años, 5 meses
Puntos: 834
Respuesta: AJAX, al descargar binario, los caracteres 127+ se evalúan en 65533

A mi me sucede lo mismo, pero se corrige así:
Código PHP:
<?php
header
('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="image.bmp"');
for( 
$i=0$i 256$i++) echo utf8_encodechr$i));
?>
  #5 (permalink)  
Antiguo 24/07/2011, 13:58
Avatar de Escain  
Fecha de Ingreso: enero-2007
Mensajes: 21
Antigüedad: 17 años, 10 meses
Puntos: 3
Respuesta: AJAX, al descargar binario, los caracteres 127+ se evalúan en 65533

Gracias por la aportación Panino.
Efectivamente el envío funciona de esta forma. El problema seguía sin embargo existiendo puesto que las imágenes que tengo que transmitir no son generadas en php sino directamente descargadas, sin que haya un tratamiento intermedio (tal como en el ejemplo que he subido online).
Había que conseguir el mismo resultado modificando únicamente el lado del cliente, es decir, javascript.

He estado buscando pues acerca de las cabeceras de envío y me he topado con una línea que ha solucionado parcialmente el problema:
Código:
http.overrideMimeType('text/plain; charset=x-user-defined');
A partir de este momento la imagen si bien no se codificaba bien, no sufre perdida de información: todos los códigos ascii tienen su equivalente único.
Finalmente, investigando en W3C y con un retoque, quedó así:
Código:
http.overrideMimeType('image/bmp; charset=iso-8859-1');
Gracias por las aportaciones.
  #6 (permalink)  
Antiguo 25/07/2011, 11:21
Avatar de zerokilled
Javascripter
 
Fecha de Ingreso: abril-2009
Ubicación: Isla del Encanto, La Borinqueña [+>==]
Mensajes: 8.050
Antigüedad: 15 años, 6 meses
Puntos: 1485
Respuesta: AJAX, al descargar binario, los caracteres 127+ se evalúan en 65533

¡que tal gente! llevo horas tratando de comprender esto y todavía no llego a algo conclusivo. siempre habia jurado que ajax recibe el código binario en forma de string de forma correcta pero al ver este tema me doy cuenta que estuve mal. estuve buscando algo de información pero lo mucho que pude encontrar fue un artículo que habla sobre el XMLHttpRequest Level 2, el cual señala sobre la técnica de usar overrideMimeType indicando como charset x-user-defined. por lo menos a mi, cuando lo intento -tanto en firefox y chrome- ajax me sigue representando los valores incorrectos.

luego se me ocurrio hacer una prueba desde el lado servidor con php. desde php obtenía el contenido como archivo (file_get_contents), luego lo transformaba a base64 y lo imprimia por pantalla. luego desde el navegador hacia una petición ajax al documento php, convertia la respuesta a binario con atob y determinadaba si había algún byte que tuviera un valor mayor de 0xff. el resultado, todos los bytes estaban correctos.

la conclusión que llegue es que el problema no es el servidor, sino el navegador o javascript. aparentemente uno de los dos no puede hacer una transformación correcta de datos binarios a una representación binaria en string. parece como si al navegador determinar que es un tipo de documento distinto, el navegador lo analiza con la misma aplicación (decoder) que normalmente utiliza para representar dicho contenido en el navegador. nota: esto solo sucede si el navegador interpreta el documento en un content-type distinto a text/*.
__________________
la maldad es una virtud humana,
y la espiritualidad es la lucha del hombre contra su maldad.
  #7 (permalink)  
Antiguo 27/07/2011, 12:39
Avatar de Escain  
Fecha de Ingreso: enero-2007
Mensajes: 21
Antigüedad: 17 años, 10 meses
Puntos: 3
Respuesta: AJAX, al descargar binario, los caracteres 127+ se evalúan en 65533

El problema de codificar antes de enviar es que el contenido ocupa bastante más, sin contar la carga para el servidor de leer y generar el contenido codificado. Por supuesto se podrían guardar los archivos ya codificados.

He hecho un cargador de imágenes ajax, simplemente para comprobar la transmisión de los archivos. Os paso el código aquí:

Código:
!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="es">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>example</title>
</head>

<body>
<script type="text/javascript">
var Http;
var http;
function Solicitudes( ){
		// Obtencion de la funcion de creacion de httpRequest.
		var factories = [
			function() { return new XMLHttpRequest();},
			function() { return new ActiveXObject( "Msxml2.XMLHTTP");},
			function() { return new ActiveXObject( "Microsoft.XMLHTTP");}
		];
		Http = null;
		for( var i = 0; i < factories.length; i++ ){
			try{
				var request = factories[i]();
				if(request != null ){
					Http = factories[i];
				}
				delete request;
			}
			catch(e){
				continue;
			}
		}
		
		
		http = Http();
		http.onreadystatechange = callbacksend;
		http.open("get", "logoEscainX.png", true);
		http.overrideMimeType('text/plain; charset=x-user-defined');
		http.setRequestHeader("accept-charset", "iso-8859-1");
		http.send(null);
};

function callbacksend(){
	if(http.readyState == 4){
		if(http.status == 200){
			var sol=http.responseText.split("");
			for( var i=0; i < http.responseText.length; i++){
				sol[i]=String.fromCharCode(sol[i].charCodeAt(0) & 0xff);
			}
			
			var img = document.createElement("img");
			document.body.appendChild(img);
			img.src = "data:image/gif;base64," + btoa(sol.join(""));
		}
	}
}
Solicitudes( );

</script>
</body>
</html>
El resultado es bastante mediocre, solo sirve para imágenes realmente pequeñas: A partir de 100k de imágene empieza a tardar bastante.
Aunque como curiosidad no esta mal, que pena que haya que hacer el recorte byte por byte, es lo que toma tanto tiempo.

Etiquetas: 65533, ajax, download, javascript
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 20:57.