发送 JSON 字符串到 cherrypy

Sending JSON string to cherrypy

我正在尝试通过 Javascript 从单个 HTML(此文件不由 cherrypy 提供服务)文件发送 JSON 字符串到 cherrpy 服务器。

这是我的最小 cherrypy 示例 (followed the "dealing with json" part)

import cherrypy

class HelloJson(object):
    @cherrypy.expose
    @cherrypy.tools.json_in()
    def default(self):
        data = cherrypy.request.json
        print(data)
        return "Hello world!"

if __name__ == '__main__':
    cherrypy.config.update({'server.socket_port':1234})
    cherrypy.quickstart(HelloJson())

通过 python 发送 JSON 字符串工作正常

>>> requests.post('http://localhost:1234', json=json.dumps({'Hello': 'Json'}))
<Response [200]>
>>> 

cherrypy 输出也打印 json 字符串

20:59 $ ./HelloJson.py 
[24/Aug/2015:20:59:34] ENGINE Listening for SIGTERM.
[24/Aug/2015:20:59:34] ENGINE Listening for SIGUSR1.
[24/Aug/2015:20:59:34] ENGINE Listening for SIGHUP.
[24/Aug/2015:20:59:34] ENGINE Bus STARTING
CherryPy Checker:
The Application mounted at '' has an empty config.

[24/Aug/2015:20:59:34] ENGINE Started monitor thread '_TimeoutMonitor'.
[24/Aug/2015:20:59:34] ENGINE Started monitor thread 'Autoreloader'.
[24/Aug/2015:20:59:34] ENGINE Serving on http://127.0.0.1:1234
[24/Aug/2015:20:59:34] ENGINE Bus STARTED
{"Hello": "Json"}
127.0.0.1 - - [24/Aug/2015:21:00:17] "POST / HTTP/1.1" 200 12 "" "python-requests/2.7.0 CPython/3.4.3 Linux/4.1.5-1-ARCH"

所以我的单个 HTML 文件看起来像这样

<html>
<head>
<script>
function makeRequest()
{
    var insertJSON = { "my_key": "my_value" };

    var xmlhttp = new XMLHttpRequest();   // new HttpRequest instance 
    xmlhttp.open("POST", "http://localhost:1234");
    xmlhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
    xmlhttp.send(JSON.stringify(insertJSON));

}
</script>
</head>
<body>
<form name="frm1" id="yourTextBox" onsubmit="makeRequest()">
<input type="submit" value="Submit">
</form>
</body>
</html>

但这会导致错误AttributeError: 'Request' object has no attribute 'json'

[24/Aug/2015:21:10:36] HTTP 
Request Headers:
  CONNECTION: keep-alive
  ACCEPT-LANGUAGE: en-US,en;q=0.5
  ACCESS-CONTROL-REQUEST-HEADERS: content-type
  ACCEPT: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  USER-AGENT: Mozilla/5.0 (X11; Linux x86_64; rv:40.0) Gecko/20100101 Firefox/40.0
  ACCESS-CONTROL-REQUEST-METHOD: POST
  ACCEPT-ENCODING: gzip, deflate
  PRAGMA: no-cache
  CACHE-CONTROL: no-cache
  HOST: localhost:1234
  Remote-Addr: 127.0.0.1
  ORIGIN: null
[24/Aug/2015:21:10:36] HTTP Traceback (most recent call last):
  File "/usr/lib/python3.4/site-packages/cherrypy/_cprequest.py", line 670, in respond
    response.body = self.handler()
  File "/usr/lib/python3.4/site-packages/cherrypy/lib/encoding.py", line 217, in __call__
    self.body = self.oldhandler(*args, **kwargs)
  File "/usr/lib/python3.4/site-packages/cherrypy/_cpdispatch.py", line 61, in __call__
    return self.callable(*self.args, **self.kwargs)
  File "./HelloJson.py", line 15, in default
    data = cherrypy.request.json
  File "/usr/lib/python3.4/site-packages/cherrypy/__init__.py", line 224, in __getattr__
    return getattr(child, name)
AttributeError: 'Request' object has no attribute 'json'

127.0.0.1 - - [24/Aug/2015:21:10:36] "OPTIONS / HTTP/1.1" 500 1515 "" "Mozilla/5.0 (X11; Linux x86_64; rv:40.0) Gecko/20100101 Firefox/40.0"

我不知道我做错了什么。

您看到的 OPTIONS 请求是 CORS preflight request, which obviously isn't a JSON request and you see the error. Because you open your file from file:// protocol (or another host), and CherryPy is serving on http://127.0.0.1:1234 you do a cross-domain request, which is subject to Same-Origin Policy

解决此问题的最简单方法是同时通过 CherryPy (Static content serving). The hard way is to provide proper CORS headers to allow cross domain requests (see )

提供 HTML 文件

我同意 saaj 的回应,即浏览器发送 CORS 预检请求,可以按以下方式处理:

import cherrypy

class HelloJson(object):
    @cherrypy.expose
    @cherrypy.tools.json_in()
    def POST(self):
        data = cherrypy.request.json
        print(data)
        return "Hello world!"

    def OPTIONS(self):
        cherrypy.response.headers["Access-Control-Allow-Methods"] = "POST, OPTIONS"
        cherrypy.response.headers["Access-Control-Allow-Credentials"] = "true"
        cherrypy.response.headers["Access-Control-Max-Age"] = "86400"
        cherrypy.response.headers[
            "Access-Control-Allow-Headers"] = "X-Mobile, Authorization, Origin, X-Requested-With, Content-Type, Accept"
        cherrypy.response.headers["Content-Type"] = "application/json; charset=utf-8"
        return ''


if __name__ == '__main__':
    cherrypy.config.update({
            'server.socket_port':1234, 
            'request.dispatch': cherrypy.dispatch.MethodDispatcher()
    })
    cherrypy.quickstart(HelloJson(), '/')

这会起作用,因为现在您已启用 API 后端来侦听浏览器的 OPTIONS 调用,该调用告诉浏览器允许的方法和来源是什么。 cherrypy.dispatch.MethodDispatcher() 使您能够将 class 视为方法调度程序,因此您可以使用 class 服务 RESTFUL API.