I'm getting a 405 error when I don't actually use a request body for successive identical requests.
Example:
app = Flask(__name__)
CORS(app)
#app.route("/login", methods=["POST"])
def login():
return jsonify({'success': True})
Request body is pretty simple:
{'username': 'foo', 'password': 'bar'}
Flutter code generating request:
http.Response response = await http.post(
Uri.parse("http://127.0.0.1:5000/login"),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{
'username': username,
'password': username,
}),
);
Term output:
127.0.0.1 - - [10/May/2022 05:37:36] "OPTIONS /login HTTP/1.1" 200 -
127.0.0.1 - - [10/May/2022 05:37:36] "POST /login HTTP/1.1" 200 -
127.0.0.1 - - [10/May/2022 05:37:41] "{"username":"foo","password":"bar"}POST /login HTTP/1.1" 405 -
127.0.0.1 - - [10/May/2022 05:37:55] "{"username":"foo","password":"bar"}OPTIONS /login HTTP/1.1" 405 -
This is greatly simplified, but is enough to produce the expected error.
However, this Flask code does not generate the same error:
#app.route("/login", methods=["POST"])
def login():
print(request.json['username'])
return jsonify({'success': True})
And term output:
127.0.0.1 - - [10/May/2022 05:58:54] "POST /login HTTP/1.1" 200 -
127.0.0.1 - - [10/May/2022 06:08:16] "OPTIONS /login HTTP/1.1" 200 -
foo
127.0.0.1 - - [10/May/2022 06:08:16] "POST /login HTTP/1.1" 200 -
foo
127.0.0.1 - - [10/May/2022 06:08:16] "POST /login HTTP/1.1" 200 -
foo
I realize this is a stupid scenario, because when wouldn't you actually use the data? I just ran into this while tinkering and lost an hour figuring out why it was throwing the error.
My question is: Why does it throw a 405 error and what is the actual difference? Does the data persist between requests if you don't access it? Is this intended functionality, and is there documentation that covers this?
This was fixed in Werkzeug 2.1.2: https://github.com/pallets/werkzeug/issues/2397
Related
i running tavern-ci test and i have url encoded:
in tavern:
test_name: test 1
stages:
- name: test 1
request:
url: 'http://127.0.0.1/check?"&#
method: GET
response:
status_code: 200
i show in the log
"GET /check?%22&# HTTP/1.1" 200
^ i do not dont want %22 i want "
but i run curl i show
"GET /check?"&# HTTP/1.1" 200
i dont want url encoded in tavern how to off so i can have real character
I'am using default cherrypy logger.
I have log every access request to my server. For GET request i have full info, like
127.0.0.1 - - [06/Jul/2021:16:10:28] "GET /test/?contract_id=228322 HTTP/1.0" 200 33
But for POST request i can't log query params or body.
127.0.0.1 - - [06/Jul/2021:13:21:03] "POST /test HTTP/1.0" 201 169
So how can i log POST query's body?
You can create tool like
def response_logging():
cherrypy.log.access_log.info(
'[{time}] {ip} "{user_agent}" {request_line} "{query_params}" "{body}" "{status}" {response}'.format(
time=datetime.now().strftime("%d/%m/%Y:%H:%M:%S"),
ip=cherrypy.request.remote.ip,
user_agent=cherrypy.request.headers["User-Agent"],
request_line=cherrypy.request.request_line,
query_params=cherrypy.request.body.request_params or "",
body=cherrypy.request.json if hasattr(cherrypy.request, "json") else "",
status=cherrypy.response.status,
response=cherrypy.response.body
)
)
cherrypy.tools.response_logging = cherrypy.Tool('on_end_request', response_logging)
print(cherrypy.request.params) # Prints params on querystring
print(cherrypy.request.headers) # Prints received headers on request
print(cherrypy.request.body) # Prints Body received
I'm writing a simple Flask application in which I want to send some data from the front-end to the Flask app, have it perform some operations, and return new data to the front-end for display. I have made similar applications before, and by returning the POST response object, instead of render_template(), I'm able to simply return the data and do what I want with it on the front-end. However, this time I'm having problems.
I make a POST request from the Jquery in the front-end. Everything seems to work fine, I can see the data being returned in the browser console, except the page reloads before I can display the new data. It reloads to http://xxx.x.x.x:5000/?.
I can see the get request for /? in the Flask console. I'd like to know why it is doing this, and how I can get it to stop.
(I've found this difficult to research because most search engines will silently ignore any question marks in a query.)
Flask app:
import json
from flask import Flask, Response, render_template, request
from src.simple_lookup import analogy_lookup
app = Flask(__name__)
app.config['DEBUG'] = True
#app.route('/')
def hello_world():
return render_template('index.html', results=['a', 'b'])
#app.route('/get_words_simple', methods=['POST'])
def get_words_simple():
print('request.form:', request.form.keys)
data = analogy_lookup(request.form['keyword'], request.form['base'], request.form['goal'])
resp = Response(json.dumps(data), status=200, mimetype='application/json')
print('data:', data)
print('resp:', resp)
return resp
if __name__ == "__main__":
app.run()
Jquery:
$.post('get_words_simple?', data, function(json, status) {
console.log('response:', json);
if (json.hasOwnProperty('error')) {
$('.results').append('<p>' + json.error);
return;
}
var words = json.words;
$.each(words, function(i, text) {
var p = $("<p>");
p.append(text);
$('.results').append(p);
});
});
Flask console:
127.0.0.1 - - [27/Dec/2018 11:12:21] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [27/Dec/2018 11:12:21] "GET /static/js/main.js HTTP/1.1" 200 -
request.form: <bound method MultiDict.keys of ImmutableMultiDict([('keyword', ''), ('base', ''), ('goal', '')])>
127.0.0.1 - - [27/Dec/2018 11:12:23] "GET /? HTTP/1.1" 200 -
127.0.0.1 - - [27/Dec/2018 11:12:23] "GET /static/js/main.js HTTP/1.1" 200 -
data: ['obtuvo', 'takata', 'stadshypotek', 'kriwet', 'shafiee', 'martorell', 'collum', '29,400', 'muteesa', 'patzek']
resp: <Response 111 bytes [200 OK]>
127.0.0.1 - - [27/Dec/2018 11:12:23] "POST /get_words_simple? HTTP/1.1" 200 -
Problem was that Bootstrap overrides type="submit" button functionality if it's in a form group. So my Jquery was doing everything right, but something about the html of the button was screwing everything up and trying to make a post request in a different way
I've found a number of simple web servers in python that will spin up a quick server and respond to requests simply. What I need is a server that won't just print the IP address, timestamp, method, and response code of each request (127.0.0.1 - - [28/Aug/2017 10:42:11] "POST / HTTP/1.1" 200 -), but also, if a POST request, I need it to print out the POST data.
So for example, if I send a POST request with {"foo":"bar"} in the body of the message, I want the server to print 127.0.0.1 - - [28/Aug/2017 10:42:11] "POST / HTTP/1.1" 200 - {"foo":"bar"} to the console before responding.
I'm not sure how to modify any of the linked options above to do this. If there's another simple option, that would work as well.
To just print out whatever JSON gets sent to a server, build yourself a basic catch-all endpoint and just print the JSON from it. In flask, this looks like the following:
import logging
from flask import Flask, request
app = Flask(__name__)
#app.route('/', methods=['POST', 'GET'], defaults={'path': ''})
#app.route('/<path:path>', methods=['POST', 'GET'])
def index(path):
print("HTTP {} to URL /{} received JSON {}".format(request.method, path, request.get_json()))
return "True"
Here's my calls to the server:
In [15]: requests.post('http://localhost:5000/', json={'a': 1})
Out[15]: <Response [200]>
In [16]: requests.post('http://localhost:5000/some/endpoint', json={'a': 1})
Out[16]: <Response [200]>
In [17]: requests.get('http://localhost:5000/', json={'a': 1})
Out[17]: <Response [200]>
Here's the server output:
In [7]: app.run(host='0.0.0.0')
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
HTTP POST to URL / received JSON {'a': 1}
127.0.0.1 - - [28/Aug/2017 11:57:49] "POST / HTTP/1.1" 200 -
HTTP POST to URL /some/endpoint received JSON {'a': 1}
127.0.0.1 - - [28/Aug/2017 11:57:51] "POST /some/endpoint HTTP/1.1" 200 -
HTTP GET to URL / received JSON {'a': 1}
127.0.0.1 - - [28/Aug/2017 11:57:55] "GET / HTTP/1.1" 200 -
Original Answer
A simple decorator should do the trick:
from flask import Flask, request
app = Flask(__name__)
def print_if_post(*args, **kwargs):
def inner_decorator(f):
def inner(*args, **kwargs):
if request.method == 'POST':
json = request.get_json()
print("JSON Data: {}".format(json))
return f(*args, **kwargs)
return app.route(*args, **kwargs)(inner)
return inner_decorator
This decorator will function exactly like app.route, but will print any JSON data sent to its endpoint:
#print_if_post('/', methods=['POST', 'GET'])
def index():
return "True"
Called with the following code:
In [4]: requests.get('http://localhost:5000/')
Out[4]: <Response [200]>
In [5]: requests.post('http://localhost:5000/', json={'a': 1})
Out[5]: <Response [200]>
Server outputs:
In [2]: app.run(host='0.0.0.0')
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [28/Aug/2017 11:03:11] "GET / HTTP/1.1" 200 -
JSON Data: {'a': 1}
127.0.0.1 - - [28/Aug/2017 11:03:23] "POST / HTTP/1.1" 200 -
I am trying to get socketio working correctly. When I load my page with following javascript. It tries to pull the socket.io page as expected but get a 404 not found each time.
<div id="result"></div>
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="//code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
<script src="https://cdn.socket.io/socket.io-1.2.1.js"></script>
<script>
$(function(){
var socket = io.connect('/endpoint');
// on receive append data.sound and linebreak to result id on page
socket.on('receive', function(data){
$('#result').append(data.mytext);
});
$('form#emit').submit(function(event) {
socket.emit('submit', {account: $('#account').val(),
...
Here is the flask endpoint for the socketIO to use
#app.route('/socket.io/<path:remaining>')
def iocg(remaining):
from websocketinstructions import WebSocketInstructions
socketio_manage(request.environ, {'/endpoint': WebSocketInstructions}, request)
return 'done'
127.0.0.1 - - [2014-11-24 15:29:05] "GET /socket.io/?EIO=3&transport=polling&t=1416864545405-114 HTTP/1.1" 404 342 0.002768
127.0.0.1 - - [2014-11-24 15:29:06] "GET /socket.io/?EIO=3&transport=polling&t=1416864546666-4 HTTP/1.1" 404 342 0.002745
127.0.0.1 - - [2014-11-24 15:29:10] "GET /socket.io/?EIO=3&transport=polling&t=1416864550413-115 HTTP/1.1" 404 342 0.003090
127.0.0.1 - - [2014-11-24 15:29:11] "GET /socket.io/?EIO=3&transport=polling&t=1416864551672-5 HTTP/1.1" 404 342 0.003325
127.0.0.1 - - [2014-11-24 15:29:15] "GET /socket.io/?EIO=3&transport=polling&t=1416864555419-116 HTTP/1.1" 404 342 0.003315
127.0.0.1 - - [2014-11-24 15:29:16] "GET /socket.io/?EIO=3&transport=polling&t=1416864556678-6 HTT P/1.1" 404 342 0.002707
127.0.0.1 - - [2014-11-24 15:29:20] "GET /socket.io/?EIO=3&transport=polling&t=1416864560425-117 HTTP/1.1" 404 342 0.002710
127.0.0.1 - - [2014-11-24 15:29:21] "GET /socket.io/?EIO=3&transport=polling&t=1416864561684-7 HTTP/1.1" 404 342 0.003227
First, check if the link to the CDN is valid. If doesn't work, change it to a new link from here, for example:
https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.5/socket.io.min.js