2012-05-23 44 views
8

Tengo Apache2 instalado y Python en funcionamiento.Publicar JSON en Python CGI

Tengo un problema. Tengo dos páginas

Una una página Python y el otro una página HTML con jQuery

Puede alguien por favor dígame cómo puedo conseguir mi ajax post para funcionar correctamente.

<html> 
<head> 

</head> 
<body> 
<script> 
    $(function() 
    { 
     alert('Im going to start processing'); 

     $.ajax({ 
      url: "saveList.py", 
      type: "post", 
      data: {'param':{"hello":"world"}}, 
      dataType: "application/json", 
      success : function(response) 
      { 
       alert(response); 
      } 
     }); 
    }); 
</script> 
</body> 
</html> 

y el código Python

import sys 
import json 

def index(req): 
    result = {'success':'true','message':'The Command Completed Successfully'}; 

    data = sys.stdin.read(); 

    myjson = json.loads(data); 

    return str(myjson); 
+0

Presumiblemente, no pasa nada? Cuéntanos los problemas que ves. –

+0

¿Está publicando un JSON o un JSON-string que está codificado en percentiles? – SuperSaiyan

+0

Solo lo quiero así que me muestra lo que publiqué, así que tengo una idea de que realmente funciona. Insistir en que en la actualidad devuelva "nulo" – TheMonkeyMan

Respuesta

9

OK, vamos a pasar a su pregunta actualizada.

En primer lugar, debe pasar la propiedad de datos Ajax en la representación de cadena. Entonces, ya que se mezcla dataType y contentType propiedades, cambiar dataType valor a "json":

$.ajax({ 
    url: "saveList.py", 
    type: "post", 
    data: JSON.stringify({'param':{"hello":"world"}}), 
    dataType: "json", 
    success: function(response) { 
     alert(response); 
    } 
}); 

Por último, modificar su código un poco para trabajar con la solicitud JSON de la siguiente manera:

#!/usr/bin/python 

import sys, json 

result = {'success':'true','message':'The Command Completed Successfully'}; 

myjson = json.load(sys.stdin) 
# Do something with 'myjson' object 

print 'Content-Type: application/json\n\n' 
print json.dumps(result) # or "json.dump(result, sys.stdout)" 

Como resultado, en el controlador success de la solicitud Ajax recibirá objeto con success y message propiedades.

+1

Está publicando 'application/json' y no' application/x-www-form-urlencoded'. Su forma de leer de stdin es correcta (IMO). Supongo que el problema está en otra parte. – SuperSaiyan

+0

@Thrustmaster ¿De qué estás hablando? Contenido predeterminadoType for * standard * La solicitud de Ajax es exactamente 'application/x-www-form-urlencoded'. ¿Por qué necesitas usar algo más? – VisioN

+1

OP está (desde su código) haciendo un HTTP/POST con cadena JSON en el cuerpo de HTTP. El tipo de contenido será 'application/json' que debería establecerse usando' $ .ajax ({contentType: "application/json"}, ...) '. Lo que sugirió allí, es url-encode cadena JSON, que, IMO, no es OP está haciendo (ya que está leyendo correctamente de stdin en el lado del servidor para eso) – SuperSaiyan

0

Debe leer datos JSON como esto:

#!/usr/bin/env python3 

import os 
import sys 
import json 

content_len = int(os.environ["CONTENT_LENGTH"]) 

req_body = sys.stdin.read(content_len) 
my_dict = json.loads(req_body) 

Con el siguiente código, puede tener problemas:

myjson = json.load(sys.stdin) 

o escrita menos sucintamente:

requ_body = sys.stdin.read() 
my_dict = json.load(requ_body) 

Eso hace me funciona cuando mi script cgi está en un servidor apache, pero no puede contar con que funcione en general, ya que descubrí cuando mi script cgi estaba en otro servidor. De acuerdo con la especificación CGI:

RFC 3875     CGI Version 1.1     October 2004 


4.2. Request Message-Body 

    Request data is accessed by the script in a system-defined method; 
    unless defined otherwise, this will be by reading the 'standard 
    input' file descriptor or file handle. 

     Request-Data = [ request-body ] [ extension-data ] 
     request-body = <CONTENT_LENGTH>OCTET 
     extension-data = *OCTET 

    A request-body is supplied with the request if the CONTENT_LENGTH is 
    not NULL. The server MUST make at least that many bytes available 
    for the script to read. The server MAY signal an end-of-file 
    condition after CONTENT_LENGTH bytes have been read or it MAY supply 
    extension data. Therefore, the script MUST NOT attempt to read more 
    than CONTENT_LENGTH bytes, even if more data is available. However, 
    it is not obliged to read any of the data. 

La línea clave es:

el guión no debe intentar leer más de bytes de CONTENT_LENGTH, incluso si hay más datos disponibles.

Al parecer, apache envía una señal de EF a la secuencia de comandos CGI inmediatamente después de enviar el cuerpo de la petición a la secuencia de comandos CGI, lo que provoca sys.stdin.read() volver. Pero de acuerdo con la especificación cgi, no se requiere que un servidor envíe una señal de eof después del cuerpo de la solicitud, y encontré que mi script cgi estaba colgado en sys.stdin.read() --cuando mi script estaba en otro servidor, lo que finalmente causó un tiempo de espera error.

Por lo tanto, con el fin de leer los datos JSON en el caso general, usted debe hacer esto:

content_len = int(os.environ["CONTENT_LENGTH"]) 

req_body = sys.stdin.read(content_len) 
my_dict = json.loads(req_body) 

el servidor establece un montón de variables de entorno para scripts CGI, que contienen la información de cabecera, uno de los cuales es CONTENT_LENGTH.

Esto es lo que una solicitud rizo no parecía cuando utilicé myjson = json.load(sys.stdin):

-v  verbose output 
-H  specify one header 
--data implicitly specifies a POST request 

Note that curl automatically calculates a Content-Length header 
for you. 

~$ curl -v \ 
> -H 'Content-Type: application/json' \ 
> --data '{"a": 1, "b": 2}' \ 
> http://localhost:65451/cgi-bin/1.py 

* Trying ::1... 
* TCP_NODELAY set 
* Connection failed 
* connect to ::1 port 65451 failed: Connection refused 
* Trying 127.0.0.1... 
* TCP_NODELAY set 
* Connected to localhost (127.0.0.1) port 65451 (#0) 
> POST /cgi-bin/1.py HTTP/1.1 
> Host: localhost:65451 
> User-Agent: curl/7.58.0 
> Accept: */* 
> Content-Type: application/json 
> Content-Length: 16 
> 
* upload completely sent off: 16 out of 16 bytes 

=== hung here for about 5 seconds ==== 

< HTTP/1.1 504 Gateway Time-out 
< Date: Thu, 08 Mar 2018 17:53:30 GMT 
< Content-Type: text/html 
< Server: inets/6.4.5 
* no chunk, no close, no size. Assume close to signal end 
< 
* Closing connection 0