415 Exception Cherrypy Webservice
Solution 1:
I've realised that the question is in fact about CORS preflight request. CORS specification defines the following condition for a simple CORS request:
- Method:
GET
,HEAD
,POST
- Headers:
Accept
,Accept-Language
,Content-Language
,Content-Type
- Cotent-type header value:
application/x-www-form-urlencoded
,multipart/form-data
,text/plain
Otherwise CORS request isn't simple, and use preflight OPTIONS request before actual request to ensure it's eligible. Here is good CORS how-to.
So if you want to keep things simple you may want to revert to normal application/x-www-form-urlencoded
. Otherwise you need to handle preflight requests correctly. Here's working example (don't forget to add localhost
alias).
#!/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)
Solution 2:
In general if you have chosen a tool, then you're better using it, instead of fighting it. CherryPy tells you that for JSON input it expects request with application/json
or text/javascript
content-type.
Here's code of 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
doesn't do anything more than removing existing body processors. If you set force
to False
, then you need to tell CherryPy how to treat the request body you send to it.
Or, better, use CherryPy and tell it correct content-type. With jQuery it's as simple as:
jQuery.ajax({
'type' : 'POST',
'dataType' : 'JSON',
'contentType' : 'application/json',
'url' : '/findRelated',
'data' : JSON.stringify({'foo': 'bar'})
});
Post a Comment for "415 Exception Cherrypy Webservice"