I am trying to build an api with flask and flask-restplus, it seems fine with no errors. When I launch the server, it look fine like this
but whatever the uri, I try to test, it displays requested URL was not found on the server and do know how to run the correspondent resource.
this is a sample of my code
#api.route('/')
class UserList(Resource):
#api.doc('list_of_registered_users')
#admin_token_required
#api.marshal_list_with(_user, envelope='data')
def get(self):
"""List all registered users"""
logger.debug('Hello from webapplib!')
return userService.get_all()
#api.expect(_user, validate=True)
#api.response(201, 'User successfully created.')
#api.doc('create a new user')
def post(self):
"""Creates a new User """
data = request.json
return save_new_user(data=data)
This is a shot in the dark, but maybe it is that simple.
I assume you were accessing /user. In your code-sample, the decorator for UserList is #api.route('/'), which corresponds to http://127.0.0.1:5000/ when running flask in the dev-server (maybe with some API-versioning path appendend, but let's ignore that for now).
Have you tried just decorating that with #api.route('/user') instead of just /?
In my Cloud9 IDE, which is running on Ubuntu I have encountered a problem in trying to reach my Python server externally. It's because their projects use a non-standard naming structure:
https://preview.c9users.io/{user}/{project}/
Changing the address to something like this, which is the default server address, doesn't help:
https://preview.c9users.io:8080/{user}/{project}/
I'm looking for a solution so I can run the following script or for a way to be able to combine HTML+JS+Python on Cloud9. The purpose of the server should be to respond to AJAX calls.
The Cloud9 server is Ubuntu-based, so there may be other ways to address this problem than just my script below.
import web
def make_text(string):
return string
urls = ('/', 'tutorial')
render = web.template.render('templates/')
app = web.application(urls, globals())
my_form = web.form.Form(
web.form.Textbox('', class_='textfield', id='textfield'),
)
class tutorial:
def GET(self):
form = my_form()
return render.tutorial(form, "Your text goes here.")
def POST(self):
form = my_form()
form.validates()
s = form.value['textfield']
return make_text(s)
if __name__ == '__main__':
app.run()
The server above actually runs and is available through URL in special format. It has been changed since earlier version, so I couldn't find it at first:
http://{workspacename}-{username}.c9users.io
Now I prefer to run it as a service (daemon) in the console window to execute additional scripts in the backend and test frontend functionality.
I have a website build using python3.4 and flask...I have generated my own self-signed certificate and I am currently testing my website through localhost.
I am using the python ssl module along with this flask extension: https://github.com/kennethreitz/flask-sslify
context = ('my-cert.pem', 'my-key.pem')
app = Flask(__name__)
sslify = SSLify(app)
...
if __name__ == '__main__':
app.debug = False
app.run(
host="127.0.0.1",
port=int("5000"),
ssl_context=context
)
This does not seem to be working however. I took a look in the sslify source code and this line does not seem to be working
def init_app(self, app):
"""Configures the configured Flask app to enforce SSL."""
app.before_request(self.redirect_to_ssl)
app.after_request(self.set_hsts_header)
Specifically the function call to redirect_to_ssl (I added my own print statement under the redirect_to_ssl function and my statement was never printed)
def redirect_to_ssl(self):
print("THIS IS WORKING")
"""Redirect incoming requests to HTTPS."""
Should we redirect?
criteria = [
request.is_secure,
current_app.debug,
request.headers.get('X-Forwarded-Proto', 'http') == 'https'
]
if not any(criteria) and not self.skip:
if request.url.startswith('http://'):
url = request.url.replace('http://', 'https://', 1)
code = 302
if self.permanent:
code = 301
r = redirect(url, code=code)
return r
I am pretty new to python. Any ideas?
To me, it appears you're making it more complicated than it needs to be. Here is the code I use in my views.py script to force user to HTTPS connections:
#app.before_request
def before_request():
if not request.is_secure:
url = request.url.replace('http://', 'https://', 1)
code = 301
return redirect(url, code=code)
According with the docs, after pip install Flask-SSLify you only need to insert the following code:
from flask import Flask
from flask_sslify import SSLify
app = Flask(__name__)
sslify = SSLify(app)
I have done it and it works very well. Am I missing something in the discussion ?
The Flask Security Guide recommends using Flask-Talisman.
$ pip install flask-talisman
Usage example:
from flask import Flask
from flask_talisman import Talisman
app = Flask(__name__)
Talisman(app)
It forces HTTPS by default (from the README):
force_https, default True, forces all non-debug connects to https.
Personally, I got some errors relating to CSP (Content Security Policy) which I disabled with:
Talisman(app, content_security_policy=None)
But use this at your own risk :)
Thanks to answer from Kelly Keller-Heikkila and comment by jaysqrd I ended up doing this in my Flask app:
from flask import request, redirect
...
#app.before_request
def before_request():
if app.env == "development":
return
if request.is_secure:
return
url = request.url.replace("http://", "https://", 1)
code = 301
return redirect(url, code=code)
I tried the flask_sslify solution suggested by Rodolfo Alvarez but ran into this issue and went with the above solution instead.
If the app is running in development mode or the request is already on https there's no need to redirect.
Here is a flask solution if you are on aws and behind a load balancer. Place it in your views.py
#app.before_request
def before_request():
scheme = request.headers.get('X-Forwarded-Proto')
if scheme and scheme == 'http' and request.url.startswith('http://'):
url = request.url.replace('http://', 'https://', 1)
code = 301
return redirect(url, code=code)
The standard solution is to wrap the request with an enforce_ssl decorator that after checking some flags in the app configuration (flags you can set depending on your debugging needs) modifies the request's url with request.url.
As it is written here.
You can modify the code to make it working with before_request as suggested by #kelly-keller-heikkila
I use a simple extra app that runs on port 80 and redirect people to https:
from flask import Flask,redirect
app = Flask(__name__)
#app.route('/')
def hello():
return redirect("https://example.com", code=302)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=80)
An alternative to the other answers that I've been able to use with great success:
from http import HTTPStatus
from typing import Optional
from flask import Response, redirect, request, url_for
def https_redirect() -> Optional[Response]:
if request.scheme == 'http':
return redirect(url_for(request.endpoint,
_scheme='https',
_external=True),
HTTPStatus.PERMANENT_REDIRECT)
# ..
if app.env == 'production':
app.before_request(https_redirect)
# ..
On app engine flex, add:
from werkzeug.middleware.proxy_fix import ProxyFix
def create_app(config=None):
app = Flask(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app)
In addition to the solution of:
#app.before_request
def before_request():
if not request.is_secure:
url = request.url.replace('http://', 'https://', 1)
code = 301
return redirect(url, code=code)
Otherwise it'll cause infinite redirects since SSL is unwrapped behind the proxy but is noted in the headers.
I ran into the same solution running a Flask application in AWS Elastic Beanstalk behind a load balancer. The following AWS docs provided two steps to configure the environment for http redirects: https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/configuring-https-httpredirect.html Following both steps fixed my issue.
One thing to note is that you'll have to create the .ebextenions folder at the root level of your application source bundle and add the config file to that .ebextensions folder. The readme here: https://github.com/awsdocs/elastic-beanstalk-samples explains this in a bit more detail.
For some reason it seems, requests from a Private AWS API Gateway with a VPC endpoint don't include the "X-Forwarded-Proto" header. This can break some of the other solutions (either it doesn't work or it continuously redirects to the same url). The following middleware forces https on most flask generated internal redirects:
class ForceHttpsRedirects:
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
environ["wsgi.url_scheme"] = "https"
return self.app(environ, start_response)
# Usage
app = flask.Flask(__name__)
app.wsgi_app = ForceHttpsRedirects(app.wsgi_app) # Add middleware to force all redirects to https
Use:
app.run(port="443")
All modern browsers automatically use HTTPS when the port is 443 or 8443.
I'm using cloud foundry python app which is behind a load balancer (like https://stackoverflow.com/users/5270172/kelly-keller-heikkila said) .
This resolution helped me by adding (_external and _Scheme to the url_for function). https://github.com/pallets/flask/issues/773
I had the same issue and mine is a brute-force solution, but it works.
Heroku in the past suggested flask_sslify, which is not maintained anymore. Nowadays the proper way in Flask should be flask-talisman, but I tried it and it has bad interactions with boostrap templates.
I tried the anulaibar solution but it did not always worked for me.
The following is what I came up with:
#app.before_request
def before_request():
# If the request is sicure it should already be https, so no need to redirect
if not request.is_secure:
currentUrl = request.url
if currentUrl.startswith('http://'):
# http://example.com -> https://example.com
# http://www.example.com -> https://www.example.com
redirectUrl = currentUrl.replace('http://', 'https://', 1)
elif currentUrl.startswith('www'):
# Here we redirect the case in which the user access the site without typing any http or https
# www.example.com -> https://www.example.com
redirectUrl = currentUrl.replace('www', 'https://www', 1)
else:
# I do not now when this may happen, just for safety
redirectUrl = 'https://www.example.com'
code = 301
return redirect(redirectUrl, code=code)
I have the domain registered in godaddy which is also redirecting to https://www.example.com.
In my case Flask app is sitting behind AWS API Gateway and solutions with #app.before_request were giving me permanent redirects.
The following simple solution finally worked:
#app.after_request
def adjust_response(response):
....
if response.location:
if app.env != "development":
response.location = response.location.replace("http://", "https://", 1)
return response
So, I have a flask application that works well when it's not deployed. Imagine it has pages for /index/ and /home/ and /home/field/. Now that I have deployed the app using Apache and mod_wsgi, it needs to have a prefix for every URL.
Now, it should look like /newapp/index/ and /newapp/home/ and /newapp/home/field/.
So, I changed all of the URLs to include the new /newapp/ prefix, but the only URL that works with it is the original /index/ URL. All of the others return a
Not Found The requested URL was not found on the server.
in the browser when I click for that URL. I definitely handle that route in my main.py, so I don't know why it would not be found.
Anyone know what is going on?
EDIT: adding some code
Basically I changed all my code in main.py from:
Original:
#app.route('/')
#app.route('/index/', methods=['GET', 'POST'])
def index():
#Stuff
#app.route('/home/')
def farms():
#More stuff
#app.route('/home/<selector>')
def fields(selector):
#Further stuff
To....
New Code
#app.route('/newapp/')
#app.route('/newapp/index/', methods=['GET', 'POST'])
def index():
#Stuff
#app.route('/newapp/home/')
def farms():
#More stuff
#app.route('/newapp/home/<selector>')
def fields(selector):
#Further stuff
I did this because the domain I am using already has another Flask app, so I had to differentiate between the two. Also, I expect there to be more flask apps in the future, so this newapp will end up being an identifier for any given flask app.
I changed main.py as well has all of my hrefs in my templates. So, the hrefs went from
href=/index/
to
href=/newapp/index/
And, I get the error that I posted above whenever I try to click on a link
Further info:
So, checking out the apache error logs one error says, File does not exist: /var/www/flask_util.js, because in my main.py I call from flask_util_js import FlaskUtilJs. I'm not sure if this has anything to do with the URL routing, but it might
You don't need to add the prefix in your code.
Say you have code like
#app.route('/hi', methods = ['GET','POST'])
def myIndex():
return "Hello World!", 200
And you set your alias like to deploy it to www.myserver.com/app/
WSGIScriptAlias /app /var/www/myDir/myApp/app.wsgi
the server should automatically map www.myserver.com/app/hi to /hi in your application.
However if you set the mapping to
#app.route('/newapp/hi', methods = ['GET','POST'])
def myIndex():
return "Hello World!", 200
You WSGI app would only receive the call for /hi (server strips away the prefix) so it would find no matching Path and return not found.
I'm using this uwsgi app:
http://projects.unbit.it/uwsgi/wiki
def application(env, start_response):
start_response('200 OK', [('Content-Type','text/html')])
return "Hello World"
I'd like to know what my current URL is, for example:
localhost:9090/some/path/here?a=b&c=d
For some reason this isn't in the docs. Am I missing something fundamental here? What should I be looking up? How do I get the current URL?
Also, how do you get stuff like:
Cookies, Accept Language, Headers, etc.
It's all in env, and wsgiref.util can help you get to it. And none of it is specific to uWSGI, which is just a WSGI container.
Most (if not all) servers is based on Apache (grandaddy). The environment is standardized.
Try: env['HTTP_HOST'], env['PATH_INFO'], env['HOST_NAME'], env['REQUEST_METHOD'], env['REQUEST_URI']