python - Why can I perform an HTTP get request to the same flask app once but not two or more times? -
the following python snippet simple flask app debugging on , 2 workers. takes sequence of ports routes , performs http request using urllib2 first port given in path, , passes along rest of ports argument.
for instance if application serving on port 4000, then
curl localhost:4000/4001
will issue http request localhost:4001
path /
for whatever reason, can 1 hop if have multiple flasks running.
port=4000 python flasky.py port=4001 python flasky.py port=4002 python flasky.py
if curl localhost:4000/
, hi
. if curl localhost:4000/4000
or curl localhost:4000/4001
, fine well. however, can't have 3 "hops" or i'll urlerror: <urlopen error [errno 111] connection refused>
, if ports involved different.
curl localhost:4000/4001/4002
fails, instance
from flask import flask import os import urllib2 import validators app = flask(__name__) def make_url(host, port, path): "make , validate url, hardcoded http protocol" assert isinstance(host, str) assert isinstance(port, str) or isinstance(port, int) assert isinstance(path, str) port = str(port) candidate_url = "http://%s:%s%s" % (host, port, path) if validators.url(candidate_url): return candidate_url else: raise valueerror(candidate_url, "is not url") # handle incoming list of ports # use first segment port , # send @app.route('/', defaults={'path': '/'}) @app.route('/<path:path>') def handle(path): # base case! if path == '/': return "hi" segments = path.split('/') # reject empty segments segments = [x x in segments if x != ''] x in range(len(segments)): segments[x] = int(segments[x]) downstream_path = "/".join(str(x) x in segments[1:]) if downstream_path == '': downstream_path = '/' # verify downstream path shorter incoming path assert len(downstream_path) < path response = urllib2.urlopen( make_url( host='127.0.0.1', port=segments[0], path=downstream_path)) html = response.read() return "hi " + html if __name__ == "__main__": app.run( host='127.0.0.1', port=int(os.environ["port"]), processes=2, debug=true)
and here full stack trace resulting curl localhost:4000/4000/4000
:
traceback (most recent call last): file "<home>/workspace/python/venv/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__ return self.wsgi_app(environ, start_response) file "<home>/workspace/python/venv/lib/python2.7/site-packages/flask/app.py", line 1820, in wsgi_app response = self.make_response(self.handle_exception(e)) file "<home>/workspace/python/venv/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception reraise(exc_type, exc_value, tb) file "<home>/workspace/python/venv/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app response = self.full_dispatch_request() file "<home>/workspace/python/venv/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request rv = self.handle_user_exception(e) file "<home>/workspace/python/venv/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception reraise(exc_type, exc_value, tb) file "<home>/workspace/python/venv/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request rv = self.dispatch_request() file "<home>/workspace/python/venv/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request return self.view_functions[rule.endpoint](**req.view_args) file "<home>/workspace/python/flasky.py", line 53, in handle path=downstream_path)) file "/usr/lib/python2.7/urllib2.py", line 154, in urlopen return opener.open(url, data, timeout) file "/usr/lib/python2.7/urllib2.py", line 431, in open response = self._open(req, data) file "/usr/lib/python2.7/urllib2.py", line 449, in _open '_open', req) file "/usr/lib/python2.7/urllib2.py", line 409, in _call_chain result = func(*args) file "/usr/lib/python2.7/urllib2.py", line 1227, in http_open return self.do_open(httplib.httpconnection, req) file "/usr/lib/python2.7/urllib2.py", line 1197, in do_open raise urlerror(err) urlerror: <urlopen error [errno 111] connection refused>
the clue in line of traceback
:
file "<home>/workspace/python/flasky.py", line 53, in handle path=downstream_path))
this means downstream_path
passing path
make_url()
not proper path.
the bug because "/".join()
not add leading /
path in url. request curl localhost:4000/4001
succeeds because there no path add request localhost:4001
.
the validator not realise error because used validators.url()
instead of validators.url.url()
.
here corrected version of code(i have commented on changes):
flask import flask import os import urllib2 import validators app = flask(__name__) def make_url(host, port, path): "make , validate url, hardcoded http protocol" assert isinstance(host, str) assert isinstance(port, str) or isinstance(port, int) assert isinstance(path, str) port = str(port) #add forward slash between port , path candidate_url = "http://%s:%s/%s" % (host, port, path) #use correct validator function here. if validators.url.url(candidate_url): return candidate_url else: raise valueerror(candidate_url, "is not url") # handle incoming list of ports # use first segment port , # send @app.route('/', defaults={'path': '/'}) @app.route('/<path:path>') def handle(path): # base case! if path == '/': return "hi" segments = path.split('/') # reject empty segments segments = [x x in segments if x != ''] x in range(len(segments)): segments[x] = int(segments[x]) downstream_path = "/".join(str(x) x in segments[1:]) #this if statement not required since explicitly #adding forward slash in make_url function. #if downstream_path == '': #downstream_path = '/' # verify downstream path shorter incoming path assert len(downstream_path) < path response = urllib2.urlopen( make_url( host='127.0.0.1', port=segments[0], path=downstream_path)) html = response.read() return "hi " + html if __name__ == "__main__": app.run( host='127.0.0.1', port=int(os.environ["port"]), processes=2, debug=true)
note: use urlparse
library create url avoid error.
Comments
Post a Comment