Is there any difference in the way redirects and requests are handled in the flask micro-framework? I have a bunch of functions which are to be run before a request is made but apparently they are not being run whenever there is a redirect to another url.
If you return redirect('someurl') in your view function it will result in a Location header being sent to the client. So unless the client decides to load the target from cache instead the view function of the target URL will be executed just like if the client accessed it directly.
Related
I have a Python application in which for one specific API, I am trying to redirect it to another API present in another Flask application. To achieve this, I am using the below code:
`
#app.route('/hello')
def hello_name(name):
return redirect("http://localhost:8000/hello", 302)
`
Now, if I try to access my API by appending query parameters like http://localhost:6000/hello?name=Sidharth, it should be redirected to http://localhost:8000/hello?name=Sidharth. Can I get an advice on how this can be done?
I looked online and found that most of the posts are advising usage of url_for() but since I don't want to redirect to another view, I don't think url_for() will be beneficial in my case. With the code that I have written now, the query parameters are not being added to the redirected url.
Try to use HTTP status code 307 Internal Redirect instead of 302 like below:-
#app.route('/hello/')
def hello_name(name):
return redirect(url_for('http://localhost:8000/hello', args1=name), code=307)
I have a Django project that contains a second, third-party Django app. In one of my views, I need to query a view from the other app (within the same Django project).
Currently, it works something like this:
import requests
def my_view(request):
data = requests.get('http://localhost/foo/bar').json()
# mangle data
return some_response
Is there a clean way to send the request without going all the way through DNS and the webserver and just go directly to the other app's view (ideally going through the middleware as well of course)
A Django view function accepts a request and returns a response object. There is no reason that a view cannot invoke another view by constructing a request (or cloning or passing its own) and interpreting the response. (c.f. the testing framework).
Of course, if the other view has undesirable side-effects, then the controlling view will have to unwind them. Working within a transaction should allow it to delve in the results of the view it invoked, and then abort the transaction and perform its own.
You can use urllib as shown below
import urllib, urllib3, urllib.request
url = "http://abcd.com" # API URL
postdata = urllib.parse.urlencode(values).encode("utf-8")
req = urllib.request.Request(url)
with urllib.request.urlopen(req, data=postdata) as response:
resp = response.read()
print(resp)
I was trying to put
session['logged_in'] = True
in the session, but in another blueprint it doesn't persist... Why is that?
Is there any better way to keep something in the session?
Extended:
I have a blueprint giving a form to login. When done and submitted, it will set a session key like above. Then it redirects via
return redirect(url_for('admin.index'))
to admin page where If I call the key via
session.get('logged_in')
I get "None" Instead of the True or False one.
I think I understand your confusion now~
Your flask session won't store anything on the server.
the 'session' dict is filled by the cookies from the client request.
Again. that is:
client make login request to server, and got a [login success] response as well as a [cookies] which contains the !!!sessionINFO!!! you think are stored on the server side.
Next time, you must send the whole cookies to the server again, then your session in the server may have data.
Browser will do this for you.
If you use a local client, say python requests library. Then be sure you are making requests with session (for requests-lib, it's requests.Session())
------------------OLD-------------------------------------
Though not an expert, but the case you described should not have happened.
The session is cookies data encrypted with a secret, if you have gone through the document mentioned by Beqa.
Just set
app.secret = '........'
And use session as a dict.
just FYI,
client request---->server (encrypt your_data 'logged_in' and client_relating_data 'maybe: ip, host or etc.', and put the encrypted info in cookies 'session=....') ------> client (get response with cookies)
client request again -----> server (decrypt the cookie 'session=...' with your secret), find the 'logged_in' data and know you are logged in.)
the cookies is something like below.
So, I'm not sure what's actually your trouble when using session, and put some basic information here. Just hope it helps in case.
I'm trying to use Twilio with Google App Engine. I'm currently trying to validate requests coming in from Twilio with SMS messages. I have a custom handler that has the 2 methods below on it.
from twilio.util import RequestValidator
class TwilioRequestHandler(BaseRequestHandler):
def twilio_request_validator(self):
return RequestValidator(AUTH_TOKEN)
def validate_request(self):
if not 'X-Twilio-Signature' in self.request.headers:
logging.error("X-Twilio-Signature was not in the request headers")
return False
return self.twilio_request_validator().validate(self.request.url, self.request.POST, self.request.headers['X-Twilio-Signature'])
When a request comes in on one of my TwiML endpoints, I call self.validate_request() from my request handler. This always seems to return false. As you can see from my code above, this should be the equivalent of calling Twilio's RequestValidator(AuthToken).validate(self.request.url, self.request.POST, self.request.headers['X-Twilio-Signature'])
I figured that it's possible that some of the request arguments that I received aren't supposed to be included when computing the signature, so I even went so far as taking the arguments for one request, creating a simple script checked all possible combinations, and compared it to the signature for that request. None of them were successful, so I have to be curious what I'm doing wrong, or if this is possibly something on the Twilio side.
Have you checked the protocol on the request URL against the Twilio endpoint?
Heroku apparently proxies HTTPS traffic to HTTP if Flask is configured for HTTP only. Flask's request.url will still begin with http:// even though Twilio is pointing at a URL that begins with https://. This will throw off hash.
I would like to know, when is the right moment and how to check the browser cookies support.
I understand I have to check the next request and for instance, with beaker, looking for the session key _creation_time or request.headers['Cookie']... and raise an exception if not found but I don't want to do that or something similar for every request. Some parts of my application don't require cookies, like the home page or info, faq page...
When a user logs out, the session gets deleted or invalidated and I used to redirect to the home view, if I check the session key at that moment, I'll not find it but it doesn't mean there is this issue.
An example I used at the beginning of login view:
try: request.headers['Cookie']
except KeyError:
return HTTPFound(location=request.route_url('home'))
Please also note that if I try to print an error message using request.session.flash(msg, 'error') or use the snippet again at the beginning of the home view and render a message with the template using a control return variable, after logout it will be erroneous displayed.
I am looking for the most elegant way to resolve issue...maybe subscribe to a event?...write down a function to call in some interested view?
There are a few things that could the cause of your problems.
Before I continue... FYI Pyramid uses WebOb to handle request and response objects
WebOb Overview
WebOb Class Documentation
Scenario 1
If you call set_cookie under Pyramid , and then do a redirect, the set_cookie will not be sent. This is because redirects create a new response object.
There are a few ways around this:
The most straightforward is to just copy response headers into the cookie when you raise/return a redirect
return HTTPfound( "/path/to/redirect", headers=[ (k,v) for (k,v)\
in self.request.response.headers.iteritems() if k == 'Set-Cookie'] )
OR
resp = HTTPFound(location='/path/to/redirect')
return self.request.response.merge_cookies(resp)
I should also note that MOST browsers accept cookies on redirects, however Safari does not.
another way is to use pyramid's hooks to convert cookies behind the scenes. i wrote subscribers that automate this. they're on pypi and github. https://github.com/jvanasco/pyramid_subscribers_cookiexfer
Scenario 2
There are two ways of handling sessions in Pyramid. Pyramid has its own session library, and then there is Beaker, which handled sessions for Pylons and has Pyramid support that many people use. I can't speak of pyramid.session, but Beaker has two modes to kill the session:
delete()
Delete the cookie, and clear the session
invalidate()
Clear the contents and start a new session
If you call invalidate(), the Beaker session cookie stays the same and all the session data is cleared -- so you can start storing new data into an empty session object.
If you call delete(), the cookie gets killed as does the session data. If you put new information into the session, IIRC, it will go into a new sessionid / cookie . However, as I noted in the first part above, set_cookie will get called but then thrown out during the redirect. So if you delete() the session and then don't migrate the set_cookie headers... the client will never receive a session identifier.
Some example behaviors of cookies under pyramid
Behavior of redirect
User visits site and is given cookie: SessionId=1
User clicks login
App saves login status to session "1"
App calls set_cookie with "LoggedIn=1"
App calls redirect to /home
Redirect sent, no cookies
User lands on /home
App only sees cookie for "SessionId=1"
Behavior of delete with redirect:
User clicks logout
App calls 'delete()' on session, killing the datastore and placing a set_cookie in request.response to expire the old cookie. if a new sessionid is created, that is sent as well.
If app renders a response, then client receives cookies
If app redirects, client does not receive headers to expire the cookie or set up a new one
Behavior of invalidate with redirect:
User clicks logout
App calls 'invalidate()' on session, killing the datastore
App sets a custom "loggedout=0" cookie
If app renders a response, then client receives cookies
If app redirects:
Client does not receive "loggedout=0" header
Client still has the old session cookie, but it was invalidated/purged on the backend, so they are effectively locked out.
side note: I personally don't like using the request.headers interface -- which handles all headers -- to get at cookies. I've had better luck with request.cookies -- which returns a dictionary of cookies.