[我正在尝试通过Javascript将单个HTML(此文件不由Cherrypy提供)文件中的JSON字符串发送到cherrpy服务器。
这是我的小例子(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,显然不是JSON请求,您会看到错误。由于您是从file://
协议(或其他主机)打开文件的,并且CherryPy在http://127.0.0.1:1234
上运行,因此您需要执行跨域请求,该请求受Same-Origin Policy的约束。
解决此问题的最简单方法是也通过CherryPy(Static content serving)提供HTML文件。困难的方法是提供适当的CORS标头,以允许跨域请求(请参阅this answer)
我同意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()
使您可以将类视为方法分派器,因此可以使用该类提供RESTFUL API。