Django return custom HTTP status text - python

I'm trying to be compatible with an app-side bug(). I want to return a response with custom HTTP message
For example, I get HTTP/1.1 429 TOO_MANY_REQUESTS now, I want get HTTP/1.1 429 CUSTOM_MESSAGE
Howerver, I can get only h2 200

Django has HttpResponse objects to build custom responses.
The following should do the trick:
from django.http import HttpResponse
response = HttpResponse("CUSTOM MESSAGE", status=429, headers={"CUSTOM_MESSAGE": "..."})
see: https://docs.djangoproject.com/en/4.1/ref/request-response/#id4

Updating HttpResponse.reason_phrase work for me, but HTTP/2.0 message will not show reason phrase, I could only find it in HTTP/1.1 message
see: https://docs.djangoproject.com/en/4.1/ref/request-response/#django.http.HttpResponse.reason_phrase

Related

Set the HTTP status text in a Flask response

How can I set the HTTP status text for a response in Flask?
I know I can return a string with a status code
#app.route('/knockknock')
def knockknock():
return "sleeping, try later", 500
But that sets the body, I'd like to change the HTTP status text from "INTERNAL SERVER ERROR" to "sleeping, try later".
It seems this is not possible in Flask/Werkzeug. It's not mentioned anywhere. But maybe I'm missing something?
The following will work in Flask. Flask can use either a status code or description while returning response. The description can obviously contain the code as well (from the client side it is identical). However note that this doesn't generate the default error description from the Flask side.
from flask import Flask
app = Flask(__name__)
#app.route('/knockknock')
def knockknock():
return "", "500 sleeping, try later"
Here is the output from the curl command,
curl -i http://127.0.0.1:5000/knockknock
HTTP/1.0 500 sleeping, try later
Content-Type: text/html; charset=utf-8
I'm not an expert on this, but I'm afraid this will only be possible through monkeypatching.
Flask returns werkzeug Response objects, and it seems that the status code reasons are hardcoded in http.py.
Again, some monkeypatching might be enough to change this for your application however.
Maybe this document will be helpful,you can customorize your own error page.
http://flask.pocoo.org/docs/0.12/patterns/errorpages/
by review the source code, in app.py can find
if status is not None:
if isinstance(status, string_types):
rv.status = status
else:
rv.status_code = status
so using
#app.route('/test')
def tt():
return "status error", "500 msg"
works.
Sorry for the misunderstanding.

Django Status 200 but 'Failed to Load Response Data" On Certain Image Uploads

I'm making an ajax post request to the Python Django view below which always return a success json response.
# views.py
#csrf_exempt
def success_response(request):
"""
Returns a http response with a JSON success state
:param request:
:return:
"""
return JsonResponse({'success': True})
In each ajax post request, i'm attaching an image file in enctype=multipart/form-data format. As you can see, here is an example request payload:
------WebKitFormBoundarymYCuLcqA6kEkqMA7
Content-Disposition: form-data; name="file"; filename="willprobablycrash.png"
Content-Type: image/png
------WebKitFormBoundarymYCuLcqA6kEkqMA7--
How is it possible that images below a certain image dimension (below 960px x 1141px) return the intended response {"success": true} while images above the said dimension return Failed to Load Response Data?
In both success and error cases, the status_code in the response is 200.
Surprisingly, it is possible for http to return status_code 200 while failing to load the response data. Which resulted in the error i had above: Failed to Load Response Data. In this case, it was my server core code (Django) being able to send the response but there was no data included due to some issues with the resolvers within the framework. After i fixed those issues, i could receive 200 + the response data that i needed.
It because of Advertising blocker chrome extensions on your browser

How can I unit test django messages... with a HTTPResponseRedirect?

Just like this question... but harder.
I have a view that redirects a user, and uses the Django messages framework to send them to the right page, and adds a message with code like that below:
def new_comment(request,pid):
post = get_object_or_404(DiscussionPost,pk=pid)
if post.closed:
messages.error(request, _('This post is closed. Your comment was not added.'))
return HttpResponseRedirect(reverse("discussionsPost",args=[post.pk]))
Now this works well for a user, but when testing the messages aren't available.
In the unit test I do:
response = self.client.post(reverse('aristotle:discussionsPostNewComment',args=[p1.id]),
{'body':"Post is closed, so I can NOT comment."}
)
#the below assertion passes
self.assertRedirects(response,reverse('aristotle:discussionsPost',args=[p1.id]))
print response
print response.context['messages']
And the first print gives:
Vary: Accept-Language, Cookie
X-Frame-Options: SAMEORIGIN
Content-Type: text/html; charset=utf-8
Location: http://testserver/discussions/post/1
Content-Language: en
With the second failing with the error:
Traceback (most recent call last):
File "/home/ubuntu/workspace/aristotle_mdr/tests/main/test_discussions.py", line 393, in test_post_to_closed_discussion
print response.context['messages']
TypeError: 'NoneType' object has no attribute '__getitem__'
Plus there its not possible to use messages.get_messages as there is no request item that can be used.
Since, there is no context dictionary in HTTPResponseRedirect, how can I check whether the message was sent properly?
If you want to test the response after the redirect, then you need to tell the Django test client to "follow" the redirect chain, via the follow argument. As stated in the Django documentation:
If you set follow to True the client will follow any redirects and a redirect_chain attribute will be set in the response object containing tuples of the intermediate urls and status codes.
So your test post would need to look something like:
response = self.client.post(
reverse('aristotle:discussionsPostNewComment', args=[p1.id]),
{'body':"Post is closed, so I can NOT comment."},
follow=True
)

Flask Json Request 400 logging?

I wrote my own custom client which sends raw http requests via my wifi card to my flask webserver.
This is what a typical requests looks like:
Content-Length: 214
User-Agent: blah
Connection: close
Host: 1.2.3.4:5000
Content-Type: application/json
{"data":[{"scoutId":2,"message":"ph=5.65"},{"scoutId":4,"message":"ph=4.28"},{"scoutId":3,"message":"ph=4.28"},{"scoutId":2,"message":"ph=5.65"},{"scoutId":4,"message":"ph=4.28"},{"scoutId":3,"message":"ph=4.30"}]}
Sometimes, my clients screw up and send malformed JSON requests to my flask server. Typically, flask will just display:
1.2.3.5 - - [01/Sep/2014 22:13:03] "POST / HTTP/1.1" 400 -
and nothing informative about the request.
I would like to track every single request that resulted in 400 in my environment and analyze what is causing these errors.
Where can I place my custom error function in my flask server?
Try turning this on:
app.config['TRAP_BAD_REQUEST_ERRORS'] = True
This should make flask raise an exception instead of just logging the 400 (see documentation here).
If you need to do something more than that, make an event handler:
http://flask.pocoo.org/docs/0.10/patterns/errorpages/
#app.errorhandler(400)
def page_not_found(exc):
#do something with the exception object `exc` here
....
Or try wrapping the body of your view function in try/except.

bottle request.json getting a 405 on post

I'm trying to get bottle to receive json in an xmlhttprequest and I'm getting a 405 error
Part of my bottle script:
#app.route('/myroute/')
def myroute():
print request.json
Part of my other script to test the xhr out:
jdata = json.dumps({"foo":"bar"})
urllib2.urlopen("http://location/app/myroute/", jdata)
Why am I getting a 405?
bottlepy error: 127.0.0.1 - - [2012-09-23 23:09:34] "POST /myroute/ HTTP/1.0" 405 911 0.005458
urllib2 error: urllib2.HTTPError: HTTP Error 405: Method Not Allowed
I also tried variations of:
#app.route('/myroute/json:json#[1-9]+#')
def myroute(json):
request.content_type = 'application/json'
print request.json, json
Returning json does not seem to be an issue
I think the problem is the server does not allow POST requests. You can probably try sending it in a GET request instead:
urllib2.urlopen("http://location/app/myroute/?" + jdata)
UPDATE:
I just realized, after looking at your question again, that you are actually trying to send JSON data via GET request. You should in general avoid sending JSONs with GET requests, but use POST requests instead[Reference].
To send a POST request to Bottle, you also need to set the headers to application/json:
headers = {}
headers['Content-Type'] = 'application/json'
jdata = json.dumps({"foo":"bar"})
urllib2.urlopen("http://location/app/myroute/", jdata, headers)
Then, with the help of #Anton's answer, you can access the JSON data in your view like this:
#app.post('/myroute/')
def myroute():
print request.json
Also, as a bonus, to send a normal GET request and access it:
# send GET request
urllib2.urlopen("http://location/app/myroute/?myvar=" + "test")
# access it
#app.route('/myroute/')
def myroute():
print request.GET['myvar'] # should print "test"
By default, the route decorator makes the decorated function handle only GET requests. You need to add a method argument to tell Bottle to handle POST requests instead. To do that, you need to change:
#app.route('/myroute/')
to:
#app.route('/myroute/', method='POST')
or a shorter version:
#app.post('/myroute/')

Categories

Resources