我正在尝试构建Cherrypy / Python Web服务。我已经花费了一整天的时间来研究如何使跨域Ajax请求成为可能。终于可以了,但是现在我有下一个问题。我想我已经知道了解决方案,但是我不知道如何实现。问题是,当我发送ajax请求时,Cherrypy服务器将响应:
415 Unsupported Media Type Expected an entity of content type application/json, text/javascript Traceback (most recent call last): File "/Library/Python/2.7/site-packages/cherrypy/_cprequest.py", line 663, in respond self.body.process() File "/Library/Python/2.7/site-packages/cherrypy/_cpreqbody.py", line 996, in process super(RequestBody, self).process() File "/Library/Python/2.7/site-packages/cherrypy/_cpreqbody.py", line 538, in process self.default_proc() File "/Library/Python/2.7/site-packages/cherrypy/_cperror.py", line 411, in __call__ raise selfHTTPError: (415, u'Expected an entity of content type application/json, text/javascript')
我找到并尝试测试的解决方案是将以下行添加到配置中:
'tools.json_in.force': False
所以我尝试在以下代码中实现它:
import cherrypy import json import sys class RelatedDocuments: def index(self): return "Hello World!" @cherrypy.tools.json_out() @cherrypy.tools.json_in() def findRelated(self, **raw): #Get JSON message form request request = cherrypy.request.json result = [] #SOME CODE... return result; # Expose the index method through the web. CherryPy will never # publish methods that don't have the exposed attribute set to True. index.exposed = True findRelated.exposed = True def CORS(): cherrypy.response.headers["Access-Control-Allow-Origin"] = "*" import os.path tutconf = os.path.join(os.path.dirname(__file__), 'webserver.conf') config = { 'global': { 'server.socket_host':'127.0.0.1', 'server.socket_port': 8080, 'log.error_file' : 'Web.log', 'log.access_file' : 'Access.log' }, '/': { 'tools.CORS.on': True } } if __name__ == '__main__': cherrypy.tools.CORS = cherrypy.Tool('before_finalize', CORS) cherrypy.quickstart(RelatedDocuments(),config=config)
我在tools.CORS.on行下添加了config行,但这没有用。接下来我尝试了这个:
cherrypy.config.update({ 'tools.json_in.force': False, });
没成功。.next我试图在findRelated方法上方实现此功能:
@cherrypy.config(**{'tools.json_in.force': False})
所有的实现给我一个500错误,如果有人可以帮助我,我非常感谢。提前致谢!
我已经意识到问题实际上是关于 CORS的飞行前请求 。CORS 规范为简单的CORS请求定义了以下条件:
GET
HEAD
POST
Accept
Accept-Language
Content-Language
Content-Type
application/x-www-form-urlencoded
multipart/form-data
text/plain
否则,CORS请求并不简单,请在实际请求之前使用预检OPTIONS请求,以确保其符合要求。这是CORS的最佳做法。
因此,如果您想保持简单,则可能需要恢复正常状态application/x-www-form- urlencoded。否则,您需要正确处理预检请求。这是工作示例(不要忘记添加localhost别名)。
application/x-www-form- urlencoded
localhost
#!/usr/bin/env python # -*- coding: utf-8 -*- ''' Add localhost alias, `proxy` , in /etc/hosts. ''' import cherrypy config = { 'global' : { 'server.socket_host' : '127.0.0.1', 'server.socket_port' : 8080, 'server.thread_pool' : 8 } } def cors(): if cherrypy.request.method == 'OPTIONS': # preflign request # see http://www.w3.org/TR/cors/#cross-origin-request-with-preflight-0 cherrypy.response.headers['Access-Control-Allow-Methods'] = 'POST' cherrypy.response.headers['Access-Control-Allow-Headers'] = 'content-type' cherrypy.response.headers['Access-Control-Allow-Origin'] = '*' # tell CherryPy no avoid normal handler return True else: cherrypy.response.headers['Access-Control-Allow-Origin'] = '*' cherrypy.tools.cors = cherrypy._cptools.HandlerTool(cors) class App: @cherrypy.expose def index(self): return '''<!DOCTYPE html> <html> <head> <meta content='text/html; charset=utf-8' http-equiv='content-type'> <title>CORS AJAX JSON request</title> <script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js'></script> <script type='text/javascript'> $(document).ready(function() { $('button').on('click', function() { $.ajax({ 'type' : 'POST', 'dataType' : 'JSON', 'contentType' : 'application/json', 'url' : 'http://proxy:8080/endpoint', 'data' : JSON.stringify({'foo': 'bar'}), 'success' : function(response) { console.log(response); } }); }) }); </script> </head> <body> <button>make request</button> </body> </html> ''' @cherrypy.expose @cherrypy.config(**{'tools.cors.on': True}) @cherrypy.tools.json_in() @cherrypy.tools.json_out() def endpoint(self): data = cherrypy.request.json return data.items() if __name__ == '__main__': cherrypy.quickstart(App(), '/', config)