how to return message to ajax? - python

my ajax code:
$.ajax({
type: 'POST',
url: URL + "xyz/" ,
data: {"email": email},
success: function(data) {
alert('hello')
},
dataType: "json",
});
my handler in python + bottle framework:
def index():
if request.POST == XMLHttpRequest:
email = request.GET.get('email')
response.COOKIES['email'] = email
if check_email(email): //a method written for checking email
return some template
else:
return False //here i want to return some error message to ajax. How to
do it? And How to caught the error in ajax.
throwing error: NameError("global name 'XMLHttpRequest' is not defined",)
is bottle support it?

2 things. First, I don't see why you're trying to check to see if it's an XMLHTTPRequest? I would just check to see if data has been sent via POST. Also it looks like you're sending through POST but trying to retrieve through GET. Try:
def index():
if request.method == "POST":
email = request.POST['email']
response.COOKIES['email'] = email
if check_login(email):
return some template
else:
return False

Just return a regular 404 or 500 response. The web browser is smart enough to know about that, and calls the error callback defined in the javascript code.
For jQuery, I believe the callback is global, but I'm not sure as my jquery-fu is weak.

It doesn't make sense to check "XmlHttpRequest" in Python. That's a Javascript wrapper around a piece of browser functionality, not anything that Python knows or cares about.
If you really need to check that the POST is coming from Ajax, you can check the request headers - jQuery, like other JS frameworks, always sets a HTTP_X_REQUESTED_WITH header. And, in fact, there's an example that uses that exact header on the Bottle documentation for Accessing Request data.

Related

Handle Pyramid HTTP error messages in Javascript

I'm sure there must be an easy solution for this, but I have been unable to find it. I'm using Python Pyramid in my server and handling requests/responses with AngularJS in Javascript. I'm using the Pyramid HTTP errors to handle some cases, and I'm able to catch them using the Angular http.error() statement.
But this is where I'm stuck, I want to do something with the error messages but if I log the response I just see html code.
In Pyramid this is happening:
if exists:
# continue execution
else:
return HTTPNotFound("The object does not exist")
And in Angular:
$http.get(url)
.success(function(data) {
// do something
})
.error(function(data){
// do something with the error message
});
How would I get that specific error message from the HTTP error? (I'm using JSON as my renderer btw)
Your render is not considered if you do not return a value for renderer but return a response or exception - so do not expect json on the output unless your error handler supports that.
You can do something like this instead:
return HTTPUnprocessableEntity(body=json.dumps(yourobj/string))
And then you can retrieve the JSON in your error handler and use angular.fromJson() to read it.
Maybe a little late, but this might interest other users of Angular:
Simply call a modal to get a pop-up of the Pyramid HTML error:
function(error)
{ console.log("error is: " + error);
var modalInstance = $uibModal.open(
{
template: error,
size:'lg'
});
}
(do not forget to include $uibModal).
Very useful for debugging purposes, but not recommended for production.

Flask-wtf: csrf_token is removed from session before I can POST my form

I'm using Flask with Flask-Security (specifically Flask-WTF regarding my csrf issue) to "ease" the process of register/loggin users (not easy so far). I'm using BackboneJS on the front-end, therefore I kind of hacked the original way to use Flask-WTF. Indeed, I make an AJAX GET request on /register to get the register page (generated by Flask-Security) and I put the resulting HTML in a modal.
render: function () {
var self = this;
$.ajax({
type: 'GET',
url: Config.constants.serverGateway + "/register"
}).done(function(result){
console.log("get register done", result);
var html = self.template({ config: Config, form: result });
self.$el.html(html);
}).fail(function(error){
console.log("Could not get register token", error);
var html = this.errorTemplate({ config: Config });
self.$el.html(html);
});
return this;
}
This way I have the generated csrf, and when I POST the registration data, I send the right csrf along the user data (email and password).
submit: function () {
console.log("submit");
var self = this;
var formData = this.$el.find('form').serialize();
$.ajax({
type: 'POST',
url: Config.constants.serverGateway + "/register",
data: formData,
dataType: 'json'
}).done(function(result){
self.trigger('close');
}).fail(function(error){
console.log("Could not submit register data", error);
});
}
On the server-side, I can debug my python code to see that the csrf_token which has been generated when I requested the register page has disappeared from the session object, therefore leading to the generation of a new one, which of course didn't match the one I send with my form. The session is still the same though, as the _id is the same during the GET and the POST.
You can see the code in flask_wtf/csrf.py::generate_csrf(), which is called when creating the form object in the ::register function from flask_security/views.py
if 'csrf_token' not in session:
session['csrf_token'] = hashlib.sha1(os.urandom(64)).hexdigest()
It results in a CSRF TOKEN MISSING error.
An additionnal information, is that my front-end and back-end are delivered by the same server, as they have a different port number.
Last, when I use an href on front-end and display the page returned by the server on the 'GET' request, submitting the form works well. I just liked to display this registration form in a modal.
Thanks for your help
Okay, I finally figured out the solution to my problem. I feel like a noob (which I am).
The problem lied in the session credentials which were not sent to the server with the requests, so that the server coudldn't access the session cookie.
I found the solution in the following tutorial: http://backbonetutorials.com/cross-domain-sessions/
To send it, i added the following lines in my Backbone router initialize function:
// Use withCredentials to send the server cookies
// The server must allow this through response headers
$.ajaxPrefilter( function( options, originalOptions, jqXHR ) {
options.xhrFields = {
withCredentials: true
};
});
This makes all AJAX requests include the withCredentials = true. On the server-side, I had to set Access-Control-Allow-Credentials:true. Since I'm using flask-cors, it is done with [supports_credentials=True][2] when creating the CORS object.
(I'm answering here since I can't comment)
#junnytony Yes I have the token in my modal and I send it in my POSt request. When I debug the Flask application, I can see the toekn I sent with my POST request, the problem is that it should be compared to the one in the session to be validated, but the one in the session has disappearred, so the flask-wtf lib generates a new one, which results in a failure when comparing with the one I sent.

POST to Django safely without using forms but avoiding CSRF errors

I would like to POST data from my iOS app to my Django server — encoding it all in the URL is just impractical. I want to do this without a form, simply sending JSON data up and getting JSON data out. When I try, I’m running into this error:
Forbidden (CSRF token missing or incorrect.)
For development, I’m currently getting around this by declaring my view method to be #csrf_exempt, but I’m worried that’s unsafe for production. Is it if I’m also declaring the method #login_required?
Assuming it is unsafe, how can I solve this? I understand the approach using {% csrf_token %} in HTML templates -- I’ve used that in other Django apps -- but again, I’m not actually using a form, nor do I wish to. I’m simply encoding my request data in a JSON dictionary, and getting a JSON dictionary back. Here’s the relevant part of the client side:
NSData *data = [NSJSONSerialization dataWithJSONObject:dictWithMyData options:NSJSONWritingPrettyPrinted error:&error];
if (!data) {
if (error)
NSLog(#"NSJSONSerialization error = %#", [error localizedDescription]);
return NO;
}
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:myServerMethodUrl] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:timeout];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:data];
NSURLResponse *urlResponse = nil;
NSData *urlData = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&error];
if (error) {
NSLog(#"NSURLConnection error = %#", [error localizedDescription]);
return NO;
}
And here’s the relevant server part:
#login_required
def my_server_method(request):
data = simplejson.loads(request.body)
R = {}
# Do stuff with the data here and generate a response with JSON data in R
....
return HttpResponse(json.dumps(R), content_type="application/json")
From what I’ve learned of the CSRF mechanism, the CSRF token is valid for the entire session. So I thought I could make this work by: a) upon authentication, passing the CSRF token to my iOS client, and then b) including the token when I post my data. Here’s how I tried that.
Upon authentication in the server, I find the CSRF token with this and send it to the client:
session_csrf_token = django.middleware.csrf.get_token(request)
And I try to pass it back by modifying my client code above like so. First I augment the data I send with my session_csrf_token (stored as _csrfToken on the client upon login):
NSMutableDictionary *dictCSRF = [NSMutableDictionary dictionaryWithDictionary:dictWithMyData];
[dictCSRF setObject:_csrfToken forKey:#"csrfmiddlewaretoken"];
NSData *data = [NSJSONSerialization dataWithJSONObject:dictCSRF options:NSJSONWritingPrettyPrinted error:error];
Then I augment the request header like so:
[request setValue:_csrfToken forHTTPHeaderField:#"X-CSRF-Token"];
But it’s not working. I get the same "CSRF token missing or incorrect" error.
Any ideas how to get this to work?

JSONP web service with python

I'm writing an AJAX function that requests data from my JSON Python webservice. My AJAX request looks like:
url = "http://localhost:8001/blah"
$.ajax({
url: url,
type: 'get',
dataType: 'jsonp',
success: function(data) {
console.log('hi')
}
});
For now, my python web service has a function that handles the request to '/blah' that has the following return statement:
return json.dumps({'a':1, 'b':2 })
My AJAX function is not successfully retrieving a response from my Python Webservice, but I don't get any errors in Firebug. What is my webservice or javascript doing wrong?
What happens when you use Jquery's JSONP datatype, is that a callback function name is sent as a GET param as part of your URL, so you're actually querying something like "http://localhost:8001/blah?callback=json125348274839".
Your response from your web server should look like this:
return "%s({'a':1, 'b':2 })" % _GET_PARAMS('callback')
so your web server will return somthing like "json125348274839({'a':1, 'b':2 })"
Hope that helps!
Zack got it. My javascript was correct. I changed my python return statement to the following:
callback = request.args.get('callback')
return '{0}({1})'.format(callback, {'a':1, 'b':2})
Turn on (or add) logging in your Python web service. Inspect your web server logs... are you receiving the request from your javascript client? Is your web server logging that it is returning a response?
Possibly it depends on the framework that you are using. Is it as simple as returning a string from the handler function? Perhaps the handler is supposed to return a list of strings and, because it is not getting a list, it is returning nothing to the client. Look in your web server logs for errors.
You forgot closing quote and semicolon in the first line =)
If it is not helps, check following:
List item
What are you using as python service? Django, flask, something else? Maybe you can provide provide python code?
Also, look at the 'Net' Firebug's tab and, after ensure that request to 'url' is actually handled (not returned 404 or 50x codes, but 200), check 'Response' sub-tab.
Hope this helps!

Posting JSON and python Flask - any techniques to use the Werkzeug debugger?

Alright, I'm working with a RESTful backend on my project, and submitting data via jquery.
I must say the werkzeug debugger is excellent for debugging specially when you're a terrible python programmer as me. You throw an exception on purpose where you want to investigate, and inspect the code and variables using the html the debugger rendered.
However when you send a post request instead of a get, if you throw an exception on the backend code, of course, the browser won't render the response text.
Is there any technique I can use to render the response text, considering it has javascript and everything?
I'm trying different things such as trying to inject the response text into a popup window, like:
$.postJSON = function(url, data, callback, error_callback) {
return jQuery.ajax({
'type': 'POST',
'url': url,
'contentType': 'application/json',
'data': JSON.stringify(data),
'dataType': 'json',
'success': callback,
'error': error_callback
});
};
$.postJSON('/the_uri', {'foo': 'bar'},
function(response) {
var a = 0;
},
function(response) {
var html = response.responseText;
var my_window = window.open('', 'mywindow1', 'width=350,height=150');
$(my_window.document).find('html').html(html);
});
});
But this won't take care of the javascript very well.
Does anyone have any suggestion?
Your approach was nearly correct. I am using the following code to open the response text in a new window (not specific to Werkzeug or Flask at all):
var w = window.open('', 'debug_stuff', 'width=540,height=150');
w.document.open();
w.document.write(response.responseText);
w.document.close();
The last line is the most important. Without it, the code would behave as yours -- it would not execute any JavaScript, because the browser doesn't know the DOM has been fully loaded.
Not javascript, but have you tried to use Firebug, you can use the option for viewing the response in a new tab (Open Response in New Tab).
If you're ready to make some changes on both the client and the server code, you can try this. In your error callback you would re-send the JSON data but as a synchonous form submission. You would create the form using jQuery, give it an input tag and put your JSON in that and submit the form. Something like:
$('<form method="post" style="display:none;">')
.attr('action', 'xxx')
.append(
$('<input>').val(JSON.stringify(data))
).appendTo('body')
.submit();
On the server-side, you would have to accept JSON the regular way when the request's content type is application/json and as form data, eg:
json_string = request.form.get('__json')
if json_string:
data = json.loads(json_string)
I have never tried this but I know the problem you're having and it can waste a lot of time. If you try it I'd like to know how it works out.
Markus' answer works perfectly. thanks so much! this saved me so much hassle.
also consider assigning your handlers to a jqxhr object
http://api.jquery.com/jQuery.post/#jqxhr-object
var jqxhr = $.post(...)
then you would write to your new window
w.document.write(jqxhr.responseText);

Categories

Resources