415 excepción servicio web Cherrypy

Estoy tratando de construir un servicio web Cherrypy / Python. Ya dedico todo el día a descubrir cómo hacer posible una solicitud ajax entre dominios. Eso está finalmente funcionando, pero ahora tengo el próximo número. Creo que ya conozco la solución, pero no sé cómo implementarla. El problema es que cuando envío la solicitud ajax, el servidor Cherrypy responde con:

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

La solución que encontré, y tratando de probar, está agregando esta línea a la configuración:

 'tools.json_in.force': False 

Así que traté de implementarlo en este código:

 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) 

Agregué la línea de configuración debajo de la línea tools.CORS.on, pero eso no funcionó. Luego probé esto:

 cherrypy.config.update({ 'tools.json_in.force': False, }); 

No funcionó ni un poco … después intenté implementar esto justo encima del método findRelated:

     @cherrypy.config(**{'tools.json_in.force': False}) 

    Todas las implementaciones me dieron un error de 500, realmente aprecio que alguien me pueda ayudar. ¡Gracias por adelantado!

    Me he dado cuenta de que la pregunta es de hecho sobre la solicitud de verificación previa de CORS . La especificación CORS define la siguiente condición para una solicitud CORS simple:

    • Método: GET , HEAD , POST
    • Encabezados: Accept , Accept-Language , Content-Language , Content-Type
    • Valor de encabezado de tipo Cotent: application/x-www-form-urlencoded , multipart/form-data , text/plain

    De lo contrario, la solicitud de CORS no es simple, y use la solicitud de OPCIÓN de verificación previa antes de la solicitud real para asegurarse de que es elegible. Aquí está el buen manual de CORS .

    Por lo tanto, si desea mantener las cosas simples, puede volver a la application/x-www-form-urlencoded normal application/x-www-form-urlencoded . De lo contrario, debe manejar las solicitudes de verificación previa correctamente. Este es un ejemplo de trabajo (no olvide agregar el alias 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 '''    CORS AJAX JSON request        ''' @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) 

    En general, si ha elegido una herramienta, entonces es mejor usarla, en lugar de luchar contra ella. CherryPy le dice que para la entrada JSON espera una solicitud con application/json o text/javascript content-type.

    Aquí está el código de cherrypy.lib.jsontools.json_in :

     def json_in(content_type=[ntou('application/json'), ntou('text/javascript')], force=True, debug=False, processor=json_processor): request = cherrypy.serving.request if isinstance(content_type, basestring): content_type = [content_type] if force: if debug: cherrypy.log('Removing body processors %s' % repr(request.body.processors.keys()), 'TOOLS.JSON_IN') request.body.processors.clear() request.body.default_proc = cherrypy.HTTPError( 415, 'Expected an entity of content type %s' % ', '.join(content_type)) for ct in content_type: if debug: cherrypy.log('Adding body processor for %s' % ct, 'TOOLS.JSON_IN') request.body.processors[ct] = processor 

    force no hace nada más que eliminar los procesadores existentes del cuerpo. Si establece la force en False , debe decirle a CherryPy cómo tratar el cuerpo de solicitud que le envía.

    O, mejor, use CherryPy y dígale el tipo de contenido correcto. Con jQuery es tan simple como:

      jQuery.ajax({ 'type' : 'POST', 'dataType' : 'JSON', 'contentType' : 'application/json', 'url' : '/findRelated', 'data' : JSON.stringify({'foo': 'bar'}) });