Determine if the flask request is from JavaScript or not.
I want to create a Flask error handler that returns a JSON response if the request was from JavaScript, but returns a redirect otherwise. I tried to use request.is_xhr
but it is not correct even for JavaScript requests. How can I check if a request is JavaScript?
@app.errorhandler(Exception)
def unhandled_exception(error):
if request.is_xhr:
return flask.jsonify(error='yes')
return redirect(url_for('error'))
source to share
@Davidism's answer to this makes sense. is_xhr
was only right when a certain header was set by some JavaScript libraries. So, I set the "X-Requested-With" header to " XMLHttpRequest
" manually in '$httpProvider'
config in AngularJs
. This ensures that on the back I get is_xhr
true for the AJAX request.
app.config([
'$httpProvider',
function ($httpProvider) {
$httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
var interceptor = [
'$q',
'$rootScope',
function ($q, $rootScope) {
'responseError': function (rejection) {
if(rejection.status != undefined && rejection.status != 'undefined') {
window.location.href = '/error';
}
}
};
return service;
}
];
$httpProvider.interceptors.push(interceptor);
}
]);
source to share
There is no standard or reliable way to determine if a request is coming from a specific source like JavaScript.
is_xhr
was only right when a certain header was set by some JavaScript libraries like jQuery. The header is not sent by most JavaScript. is_xhr
for this reason is deprecated.
You can check the header Accept
to see if the client is requesting application/json
, but that is unreliable too.
if request.is_xhr or request.accept_mimetypes.accept_json:
return jsonify(...)
return redirect(...)
source to share
Instead of binding my app to a custom header, I added a header Accept:
to my Javascript:
let req = new XMLHttpRequest();
req.open('POST', location);
// signal back-end to return json instead of rendering a full page:
req.setRequestHeader('Accept', 'application/json');
req.send(…);
And in my Python:
# if an ajax-like request, return json instead of html
if request.accept_mimetypes.best == 'application/json':
log.debug('client prefers json, skipping page render.')
return jsonify(status='errror', detail='…')
This should handle other use cases as they arise.
source to share
If the request is javascript / jquery code, it is definitely from the browser, so you can check the object flask.request.user_agent
that is an instance werkzeug.useragents.UserAgent
to see if.
source to share