【问题标题】:Post JSON to Python CGI将 JSON 发布到 Python CGI
【发布时间】:2012-05-29 22:05:25
【问题描述】:

我已经安装了 Apache2 并且 Python 工作正常。

我有一个问题。我有两页。

一个是 Python 页面,另一个是带有 JQuery 的 Html 页面

谁能告诉我如何让我的 ajax 帖子正常工作。

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

还有 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);

【问题讨论】:

  • 大概什么都没有发生吧?请告诉我们您遇到的问题。
  • 您发布的是 JSON 还是百分位编码的 JSON 字符串?
  • 我只想要它,它可以显示我发布的内容,因此我知道它确实有效。安装它目前返回“null”
  • @Deano 好吧,你的问题首先不是很清楚。现在您可以查看我的答案的更新版本。它应该可以工作。
  • 为什么上面的python代码中每条语句后面都有分号?一个错误,我猜?

标签: jquery python html ajax


【解决方案1】:

为伟大的@7stud 的回答添加一点点 我在读取 unicode 时遇到了一些内容长度问题,我通过从缓冲区读取来修复:

content_length = int(os.environ["CONTENT_LENGTH"])
data = sys.stdin.buffer.read(content_length).decode('utf-8')

【讨论】:

    【解决方案2】:

    你应该像这样读取 json 数据:

    #!/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)
    

    使用以下代码,可能会遇到问题:

     myjson = json.load(sys.stdin)
    

    或者写得不太简洁:

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

    当我的 cgi 脚本在 apache 服务器上时,确实对我有用,但你不能指望它在一般情况下工作——正如我在我的 cgi 脚本打开时发现的那样另一台服务器。根据 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.
    

    关键是:

    脚本不得尝试阅读更多内容 超过 CONTENT_LENGTH 个字节,即使有更多数据可用。

    显然,apache 在将请求正文发送到 cgi 脚本后立即向 cgi 脚本发送了一个 eof 信号,这导致 sys.stdin.read() 返回。但是根据cgi规范,请求正文后不需要服务器发送eof信号,我发现我的cgi脚本挂在sys.stdin.read()--当我的脚本在另一台服务器上时,最终导致超时错误。

    因此,为了在一般情况下读取 json 数据,您应该这样做:

    content_len = int(os.environ["CONTENT_LENGTH"])
    
    req_body = sys.stdin.read(content_len)
    my_dict = json.loads(req_body)
    

    服务器为cgi脚本设置了一堆环境变量,其中包含头信息,其中一个是CONTENT_LENGTH。

    这是我使用 myjson = json.load(sys.stdin) 时失败的 curl 请求的样子:

    -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
    

    【讨论】:

      【解决方案3】:

      好的,让我们转到更新后的问题。

      首先,您应该以字符串表示形式传递 Ajax 数据属性。然后,由于您混合了dataTypecontentType 属性,请将dataType 的值更改为"json"

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

      最后,稍微修改一下代码以处理 JSON 请求,如下所示:

      #!/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)"
      

      因此,在 Ajax 请求的 success 处理程序中,您将收到具有 successmessage 属性的对象。

      【讨论】:

      • 他发布的是application/json,而不是application/x-www-form-urlencoded。他从标准输入读取的方式是正确的(IMO)。我想问题出在其他地方。
      • @Thrustmaster 你在说什么? standard Ajax 请求的默认 contentType 是 exaclty application/x-www-form-urlencoded。为什么你需要使用其他东西?
      • OP 是(来自他的代码)在 HTTP 正文中使用 JSON 字符串执行 HTTP/POST。内容类型为application/json,需要使用$.ajax({contentType:"application/json"},...) 进行设置。你在那里建议的是对 JSON 字符串进行 url 编码,IMO 不是 OP 正在做的(因为他正在从服务器端的标准输入正确读取)
      • 首先,您确定他从stdin 读取的内容正确吗? HTTP 请求与来自控制台的输入不同。接下来,他可以轻松地发送data : { first : 1, next : 2 } 而不是字符串,并在服务器端同时获得firstnextform。问题是什么?那么,你把 OP 作为内容类型发送到哪里了?为什么要这样做? OP 根本不知道如何使用纯 Python CGI 处理来自 Ajax 的发布请求。我认为你做得过火了。
      • 我一直在网上搜索如何让 cgi 识别不是从 html 表单发送的原始字符串,但找到了这个解决方案..我 3 天的深夜睡眠结束了..谢谢
      猜你喜欢
      • 2012-05-30
      • 2014-01-10
      • 1970-01-01
      • 2021-10-03
      • 1970-01-01
      • 1970-01-01
      • 2012-10-05
      相关资源
      最近更新 更多