2015-01-20 3 views
4

Cherrypy/Python webservice를 빌드하려고합니다. 나는 이미 크로스 도메인 아약스 요청을 가능케하는 방법을 찾는 데 하루 종일 쓰고 있습니다. 그게 마침내 효과가 있지만 이제 다음 문제가 생겼습니다. 이미 솔루션을 알고 있다고 생각하지만 구현 방법을 모르겠습니다.415 Cherrypy webservice

'tools.json_in.force': False 
: 구성에이 줄을 추가하고,

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

내가 찾은 솔루션 및 테스트하려고 : 문제는 내가 아약스 요청을 보낸다 때 Cherrypy 서버가 응답이다

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 라인 아래에있는 설정 라인을 추가하지만, 작동하지 않았다 :

그래서 나는이 코드를 구현하기 위해 노력했다. 다음으로이 시도 :

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

나는 findRelated 방법 위에서이 권리를 구현하기 위해 노력 eiter..next 작동하지 않았다 : 구현의 모든 나에게 500 오류, 정말 준

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

누군가가 나를 도울 수 있으면 고마워. 미리 감사드립니다!

답변

4

나는이 질문이 사실 CORS preflight request에 관한 것임을 깨달았습니다. CORS specification defines 간단한 CORS 요청에 대한 다음의 조건 :

  • 방법 : GET, HEAD, POST
  • 헤더 : Accept, Accept-Language, Content-Language, Content-Type
  • Cotent 형 헤더 값 : application/x-www-form-urlencoded, multipart/form-data, text/plain

그렇지 않으면 CORS 요청이 아닙니다. 간단하고 실제 요청 전에 프리 플라이트 OPTIONS 요청을 사용하여 자격이 있는지 확인하십시오. 여기에 good CORS how-to입니다.

따라서 단순하게 유지하려면 보통 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) 
+0

정말 고마워, 너는 내 하루를 만들었 어! 모든 것이 이제는 정상적으로 작동하며 프리 플라이트 요청에 대해 들어 본 적이 없습니다. – Chris

1

일반적으로 도구를 선택한 경우에는 도구 대신 사용하는 것이 좋습니다. CherryPy는 JSON 입력의 경우 내용 유형이 application/json 또는 text/javascript 인 요청을 기대합니다.

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

기존의 신체 프로세서를 제거보다 더 아무것도하지 않습니다

여기 cherrypy.lib.jsontools.json_in의 코드입니다. forceFalse으로 설정하면 CherryPy에 보내는 요청 본문을 처리하는 방법을 알릴 필요가 있습니다.

또는 CherryPy를 사용하여 내용 유형을 수정하십시오. jQuery는 다음과 같이 간단합니다.

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

그래, 나는 이미이 파일을 보았고 contentType은 application/json 이었다는 것을 알고있다. 하지만 POST에서 OPTIONS 메서드로 HTTP 요청이 변경되었지만 메서드를 POST로 명시 적으로 설정했습니다. 이것에 대한 정보를 발견했는데, 아마도 크로스 도메인 아약스 요청을하는 것이지만 솔루션을 찾을 수 없습니다. 난 그냥 빠른 프로토 타입을 설정하려고 했으므로 다른 솔루션을 발견하고 당분간이 문제를 바로 해결할 수 있기를 바랍니다. – Chris