I am trying to create a simple app where an array of integers is generated on the server and sent to the client. Here is some sample (working) code in app.py:
from flask import Flask, render_template, request, url_for
import random
app = Flask(__name__)
#app.route('/')
def form():
s_abc = [random.random() for _ in range(40)]
return render_template('abc.html', s_abc=s_abc)
if __name__ == '__main__':
app.run(debug=True)
And here is a (working) snippet of abc.html:
<div>
{{s_abc}}
</div>
The problem is, this code uses the GET HTTP method (which Flask uses by default when none is specified). I would like to instead use the POST HTTP method, since it is apparently more secure for sending data. (Source: http://blog.teamtreehouse.com/the-definitive-guide-to-get-vs-post)
To do this, I tried to change:
#app.route('/')
to:
#app.route('/', methods=['POST'])
Unfortunately, I got an error: "Method Not Allowed: The method is not allowed for the requested URL."
Question: How should I fix this?
[Note: From what I currently understand, I would need to create a form to use the POST method, but I don't think my website would need a form, since the client isn't sending data to the server. (In my website, the server is sending data to the client.)]
[Note: This is similar to a question I asked previously, but not the same, because here I am asking about a specific error message, Method not Allowed.]
You should not be using the POST method in this instance. The POST method is meant to be used when you are changing data on the server. In this case you are only retrieving data, so GET is the more appropriate method to use here.
In any case, if you do decide to use POST, your code is actually working. You can see this if you use a POST request to access the endpoint:
$ curl -X POST http://127.0.0.1:5000/
<div>
[0.03464541692036849, 0.5588700799957625, 0.4702806873145451, 0.7525198710149907, 0.0674801622743858, 0.28229897849445273, 0.17400190415782735, 0.48911931330821357, 0.8033543541248421, 0.16335301905982258, 0.3307436416488905, 0.11670066397858725, 0.552907551276049, 0.6699689958218984, 0.7444295210533091, 0.8258885497774587, 0.8656500198078877, 0.6826827672886756, 0.27219907080455874, 0.9053285546116574, 0.8328655798090894, 0.2323223157770763, 0.9775485685217323, 0.34887389370958166, 0.17092511319368353, 0.20875570398480459, 0.6744092445507751, 0.6176283706166301, 0.05070680888843082, 0.3441890248079591, 0.17701427714228501, 0.115329649057473, 0.325114272097177, 0.19386610624431766, 0.18892384889766745, 0.511139418514318, 0.019931284111035397, 0.5240369332606203, 0.8936272011794374, 0.9665936114223397]
</div>
If you just access the URL in your browser, this will actually send a GET request, and you have modified your code to specifically only allow the POST method - which is why you get the Method Not Allowed response.
$ curl -X GET http://127.0.0.1:5000/
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>405 Method Not Allowed</title>
<h1>Method Not Allowed</h1>
<p>The method is not allowed for the requested URL.</p>
The best solution is for you to use GET in this instance.
When you use the browser to visit a page, the browser always send 'GET' request to server... so when you've changed the methods to 'POST', flask can't find any GET route for '/' and return "Method Not Allowed" error, as the '/' doesn't allows GET anymore when browsers asks for that page.
You shouldn't use POST for this. POST only used when submitting data from forms or ajax.
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 am working on a Flask web application, and encountering an issue concerning duplicate HTTP requests.
Every time a request is made, it is sent twice (for GET requests and POST requests as well), as can be seen on the screenshot below. I am running the application in production environment and with debug mode being "off".
How could I find out why the requests are being sent twice ?
EDIT:
The view functions are indeed being called twice every time a request is made. Any ideas ?
from flask import render_template
#product.route('/', methods=['GET', 'POST'])
#login_required
def index():
print('Request to index.')
products = Product.query.all()
return render_template('product/index.html', products=products)
Chrome sends an extra GET request for a favicon. Add this to the head of your html to stop this request
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
I got question about implementing google login. I was able to implement Google Login button on my react app using an open source library called react-google-login. I was able to set up the backend server using python flask. I host my api method on the api on Heroku: http://arrangement-server.herokuapp.com/login.
And my react app runs successfully locally, and I am able to use login-in button. But, my issue is that my server displays the following error:
Method not Allowed.
Is this because it is post method?
Why is it my Server shows me that that method is not allowed?
Even though on the client side it runs fine, and I am able to see user profile and user information.
Here's the code to my backend server, you can find it at Github:
#app.route("/login", methods=['POST'])
def login():
data = request.json
session['access_token'] = data['access_token'], ''
return jsonify({'message':'You are logged in.'})
Your "login" endpoint will accept only "POST" HTTP requests. Because of this line:
#app.route("/login", methods=['POST'])
When you try to open your page in a browser - the browser will send the "GET" HTTP request to that URL.
That is why you are getting "Method Not Allowed" error.
Take a look at my answer on upwork for more details.
Your heroku server is only a backend server.
And the route "/login" accepts only POST request.
So you can't send the GET request to this route on web browser.
If you want to look at the response with this route, you can send the POST request by using POSTMAN.
I think this part
#app.route("/")
def home_page():
access_token = session.get('access_token')
if access_token is None:
return redirect(url_for('login'))
Always force user to visit login page with GET method. Unfortunately you don't have method and route defined to handle this GET method.
I'm writing an app using Flask.
I have a set of routes and they work.
What I want to do on the client side is to ignore any requests to invalid URLs. That is I do not want to render any 404/error pages in the app. I would like an alert that says the URL is invalid and for the browser to simply stay on the same page.
I don't want to be checking the URLs in JavaScript on the client, as this would expose them.
I have a route which responds correctly to unknown URLs:
#app.errorhandler(404)
def non_existant_route(error):
return jsonify({"no":"such page"})
If I delete the return statement I get a 500 error.
I can't use abort()
Does this idea violate some HTTP principle?
Thanks
It sounds like you need a "catch-all" endpoint. Typically, it seems a catch-all endpoint would return a generic 404, but in your case, you probably want to return a 200 with some contextual information. Here's basically how you can do it (credit goes to http://flask.pocoo.org/snippets/57/):
from flask import Flask
app = Flask(__name__)
#app.route('/', defaults={'path': ''})
#app.route('/<path:path>')
def catch_all(path):
# returns a 200 (not a 404) with the following contents:
return 'your custom error content\n'
# This is just one of your other valid routes:
#app.route('/stuff')
def stuff():
return 'stuff\n'
if __name__ == '__main__':
app.run()
If you run this and curl various endpoints of the test app, here's what you get:
$ curl localhost:5000/stuff
stuff
$ curl localhost:5000/foo/bar
your custom error content
$ curl localhost:5000/otherstuff
your custom error content
As you can see, your other routes will still work as you expect.
I've decided a solution to this is too hard! I can not find any way to get the browser to ignore a response. There is no response header for 'do nothing'. If there was we would probably never see a webserver error again, which would not be good.
I could ajaxify all the requests as a way to grab the response headers and analyze them before any rendering or redirecting happens. That starts to break all the navigation (back buttons at least) and the pretty URLs. I could bung in a JS routing framework etc, and while I'm leaning how it works I'm not building my app (I already have enough to learn!)
#app.errorhandler(404)
def page_not_found(error):
return redirect(url_for('index'))
If you come up with something great post it anyway, I'm not the first to ask this question, and probably not the last.
Thanks
I remember reading about a javascript library some days ago (but I don't remember the name...). The clou with this library was, that all links and form submits were loaded not directly into the browser "_top" frame/window but into a hidden div and afterwards, when done, the content of the page was replaced by the content of this hidden div.
So if you want to catch bad links and such on client side you could hook up all links and submits and check the http response code. If it is not 200 (ok) you display an error. If it is okay you decide, if you replace the old page with the new content.
But there are two problems with this solution:
1. You would have to change the browsers location (in the address bar) without reloading the page of course!
2. It might get tricky to post some file uploads with javascript.
If I find the link or name of the js-library I saw, I will tell you!
I am running a mod_python server, where the index.py is designed to handle the incoming requests.
In the index.py, if I design something like this to handle form and get the details in the form:
<form enctype="multipart/form-data" action="func" method="post">
<p>Input file:<input type="file" name="request"></p>
<p><input type="submit" name="press" value="submit"></p>
And get the details from the form like this (note the action "func" above)
def func(req):
message = []
f = req.form.getfirst('request')
It works perfectly fine from the browser. I can upload a file and its contents can retrieved at the server end.
However, I want to send data via curl's POST. In that case, I thought, the <form> element at the server is not required to handle POST, if I can get the POST data from the request object itself.
Suppose my request via curl is like this:
curl --data "request=data_i_am_posting" http://mymodpythonsite.com/path/
How should my mod_python request handler be designed so that I get the data I am posting.
Should I use the <form> at all?
def index(req):
# What should I do here to get data_i_am_posting
BTW, please note that I HTTP server wont be accessed by browser at all, the clients (curl, scripts) will post data and wait for the response which will be non-html.
First a few notes:
It looks like you're using the Publisher Handler of mod_python. This does a lot under the covers to map URL's to Python functions.
The server doesn't really know or care where its getting its data. In your case the curl command is simply simulating a form POST request.
Therefore you can handle the curl requests exactly the same as form requests.
You probably don't want to name your function "index" because that might add unnecessary confusion to the publisher's path->function mapping since "index.py" is an implied part of the path. Not wrong, just confusing.
So for your curl command, you should be able to get what you want from this function in the "index.py" module:
def path(req):
request_data = req.form.getfirst('request')
-