I'm trying to make a simple python script which returns an argument from GET request. The issue is that it does not receive any arguments and returns blank body. There is one peculiar thing, though. In order to test GET requests I use requestmaker.com, hurl.it and apikitchen.com. While requestmaker and apikitchen return an empty body, hurl.it actually returns the required parameter.
I have tried Bottle, Flask and Tornado with the same results. I'm using ngrok for tunneling but I've also tried forwardhq.com.
The code (with bottle framework):
import bottle
from bottle import route, run, request, response
bottle.debug(True)
#route('/')
def home():
return "Great Scott!"
#route('/valley')
def thevalley():
theflux = request.query.flux
return theflux
run(host='0.0.0.0', port=8515, reloader=True)
ngrok status:
Tunnel Status online
Version 1.6/1.5
Forwarding http://88mph.ngrok.com -> 127.0.0.1:8515
The results I get from GET requests:
requestmaker.com
Request Headers Sent:
GET /valley HTTP/1.1
Host: 88mph.ngrok.com
Accept: */*
Content-Length: 10
Content-Type: application/x-www-form-urlencoded
Response Headers:
HTTP/1.1 200 OK
Server: nginx/1.4.3
Date: Sun, 09 Feb 2014 13:51:20 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 0
Connection: keep-alive
bottle:
127.0.0.1 - - [09/Feb/2014 13:51:20] "GET /valley HTTP/1.1" 200 0
hurl.it
Request:
Accept: */*
Accept-Encoding: gzip, deflate, compress
User-Agent: runscope/0.1
Response:
Connection: keep-alive
Content-Length: 5
Content-Type: text/html; charset=UTF-8
Date: Sun, 09 Feb 2014 14:02:55 GMT
Server: nginx/1.4.3
Body:
121gw
bottle:
127.0.0.1 - - [09/Feb/2014 14:02:55] "GET /valley?flux=121gw HTTP/1.1" 200 5
https://88mph.ngrok.com/valley?flux=121gw
Finally, just entering the URL into the address bar works as well, I get "121gw".
bottle:
127.0.0.1 - - [09/Feb/2014 14:05:46] "GET /valley?flux=121gw HTTP/1.1" 200 5
End
Every request maker can connect to server (200 OK) and even return "Great Scott" when accessing root. However, only webbrowser and hurl return the argument. Any ideas what is at fault here?
Related
here is my code:
from fastapi import FastAPI
app = FastAPI()
#app.trace("/")
def test_trace():
...
and this is the response:
curl -v -X TRACE http://127.0.0.1:8000
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< date: Sat, 03 Sep 2022 15:52:55 GMT
< server: uvicorn
< content-length: 4
< content-type: application/json
<
* Connection #0 to host 127.0.0.1 left intact
but I want something like this with TRACE header in it:
< HTTP/1.1 200 OK
< date: Sat, 03 Sep 2022 15:52:55 GMT
< server: uvicorn
< content-length: 4
< content-type: application/json
< TRACE / HTTP/1.1
< Host: www.ssfkz.si
< User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Headers (and pretty much every detail of interest) are customizable through the use of the Response object.
from fastapi import FastAPI, Response
app = FastAPI()
#app.trace("/")
def test_trace(response: Response):
response.headers["TRACE"] = "HTTP/1.1"
response.status_code = 200
...
return {}
Before asking on SO, please make sure to read (and/or search) the official documentation (https://fastapi.tiangolo.com/advanced/response-headers/).
EDIT
Even though the OP mentioned setting the TRACE "header", officially, the implementation of this HTTP method does not mention setting such headers, but rather, returning exactly what was received in the trace request.
An approximate behavior might be achieved by using:
#app.trace("/")
def test_trace(request: Request, response: Response):
for k,v in request.headers.items():
response.headers[k] = v
# repeat for every property that should be echo-ed
response.headers["Content-Type"] = "message/http" # RFC 7231
response.status_code = 200 # RFC 7231
return {}
I have a remote server running a simple flask server on it. I use this server for debugging purposes of my MCU cellular interface.
from flask import Flask
from flask import request
app = Flask(__name__)
#app.route("/b61d39e9-94ca-49e2-96ba-bdc3325a8aeb", methods = ["POST"])
def root():
print(request.headers)
if(request.is_json):
content = request.get_json()
print (content)
print(request.form.get("uuid"))
return "OK"
if(__name__ == "__main__"):
app.run(host = "0.0.0.0", port = 65432, debug = True)
And I send this request using netcat and the command nc ... 65432 < Request.txt
POST /b61d39e9-94ca-49e2-96ba-bdc3325a8aeb HTTP/1.1
Host: ESP32-DevKit VE
Content-Type: multipart/form-data;boundary="data"
--data
Content-Disposition: form-data; name="uuid"
ff0dbd36-dc36-4df5-8196-324adf76ed3f
--data--
netcat is reporting error 200, so everything was fine, but the flask web server doesn´t output the value of the field uuid.
... - - [13/Aug/2022 09:21:21] "POST /b61d39e9-94ca-49e2-96ba-bdc3325a8aeb HTTP/1.1" 200 -
Host: ESP32-DevKit VE
Content-Type: multipart/form-data;boundary="data"
None
I can not figure out what kind of problem is here.
It appears you're missing Content-Length header. I was able to get uuid using your python code above and this request:
POST /b61d39e9-94ca-49e2-96ba-bdc3325a8aeb HTTP/1.1
Content-Type: multipart/form-data; boundary=--------------------------data
Content-Length: 135
----------------------------data
Content-Disposition: form-data; name="uuid"
ff0dbd36-dc36-4df5-8196-324adf76ed3f
----------------------------data--
Is there a way to force gunicorn to pass the handling of "HEAD" request method to a drf application?
Currently, I have a view which looks similar to the code below :-
#api_view(["POST", "GET", "DELETE", "PUT", "PATCH", "HEAD"])
#renderer_classes([ProxyRender])
def my_proxy_view(request, path=""):
return proxy_dispatch(
urljoin(settings.PROXY["ENDPOINT"], path),
request,
)
However, when sending a "HEAD" request to the endpoint it seems like gunicorn or Django is the one handling the response, not my view as invoking my view should yield a head result of the service behind.
$ curl -I "http://localhost:8000/proxy/some-endpoint"
HTTP/1.1 200 OK
Server: gunicorn
Date: Sat, 20 Aug 2022 15:29:57 GMT
Connection: close
Content-Type: application/json
Allow: HEAD, POST, PUT, DELETE, GET, PATCH, OPTIONS
X-Frame-Options: DENY
Content-Length: 106
Vary: Cookie
X-Content-Type-Options: nosniff
Referrer-Policy: same-origin
I am trying to create simple API for my site. I created the route with flask:
#api.route('/api/rate&message_id=<message_id>&performer=<performer_login>', methods=['POST'])
def api_rate_msg(message_id, performer_login):
print("RATE API ", message_id, ' ', performer_id)
return 400
print(...) function don't execute...
I use flask-socketio to communicate between client and server.
I send json from client and process it with:
#socket.on('rate')
def handle_rate(data):
print(data)
payload = {'message_id':data['message_id'], 'performer':data['performer']}
r = requests.post('/api/rate', params=payload)
print (r.status_code)
Note, that data variable is sending from client and is correct(I've checked it).
print(r.status_code) don't exec too...
Where I'm wrong? Please, sorry for my bad english :(
This api function must increase rate of message, which stored in mongodb, if interesting.
Don't put &message_id=<message_id>&performer=<performer_login> in your route string. Instead, get these arguments from request.args.
Try it:
from flask import request
...
#api.route('/api/rate', methods=['POST'])
def api_rate_msg():
print(request.args)
return ''
I've tested it with httpie:
$ http -v POST :5000/api/rate message_id==123 performer_login==foo
POST /api/rate?message_id=123&performer_login=foo HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 0
Host: localhost:5000
User-Agent: HTTPie/0.9.8
HTTP/1.0 200 OK
Content-Length: 0
Content-Type: text/html; charset=utf-8
Date: Sun, 02 Apr 2017 13:54:40 GMT
Server: Werkzeug/0.11.11 Python/2.7.13
And from flask's log:
ImmutableMultiDict([('message_id', u'123'), ('performer_login', u'foo')])
127.0.0.1 - - [02/Apr/2017 22:54:40] "POST /api/rate?message_id=123&performer_login=foo HTTP/1.1" 200 -
Remove the below part from your api route
&message_id=<message_id>&performer=<performer_login
This is not required in POST request. It helps in GET requests. API call in request is not matching the route definition and therefore you have the current problem
I'm having problems with a Flask view that should return a response with content-type "application/json" in response to a POST request.
Specifically, if I do:
curl -v -d 'foo=bar' http://example.org/jsonpost
to this view:
#app.route('/jsonpost', methods=['GET', 'POST'])
def json_post():
resp = make_response('{"test": "ok"}')
resp.headers['Content-Type'] = "application/json"
return resp
I get some sort of connection reset:
* About to connect() to example.org port 80 (#0)
* Trying xxx.xxx.xxx.xxx... connected
* Connected to example.org (xxx.xxx.xxx.xxx) port 80 (#0)
> POST /routing/jsonpost HTTP/1.1
> User-Agent: curl/7.19.7 (i486-pc-linux-gnu) libcurl/7.19.7 OpenSSL/0.9.8k zlib/1.2.3.3 libidn/1.15
> Host: example.org
> Accept: */*
> Content-Length: 7
> Content-Type: application/x-www-form-urlencoded
>
< HTTP/1.1 200 OK
< Server: nginx/1.2.4
< Date: Thu, 27 Dec 2012 14:07:59 GMT
< Content-Type: application/json
< Content-Length: 14
< Connection: keep-alive
< Set-Cookie: session="..."; Path=/; HttpOnly
< Cache-Control: public
<
* transfer closed with 14 bytes remaining to read
* Closing connection #0
curl: (18) transfer closed with 14 bytes remaining to read
If instead I do:
curl -d 'foo=bar' http://example.org/htmlpost
to:
#app.route('/htmlpost', methods=['GET', 'POST'])
def html_post():
resp = make_response('{"test": "ok"}')
resp.headers['Content-Type'] = "text/html"
return resp
I get the expected the full response (200-ok)
{"test": "ok"}
By the way, if I send a GET request to the same JSON route:
curl http://example.org/jsonpost
I also get the expected response..
Any ideas?
Thanks to Audrius's comments I tracked a possible source of the problem to the interaction between uWSGI and nginx: apparently, if you receive POST data in a request you must read it before returning a response.
This, for example, fixes my issue.
#app.route('/jsonpost', methods=['GET', 'POST'])
def json_post():
if request.method == 'POST':
dummy = request.form
resp = make_response('{"test": "ok"}')
resp.headers['Content-Type'] = "application/json"
return resp
A different solution involves passing --post-buffering 1 to uWSGI as described by uWSGI's author Roberto De Ioris.
I still don't understand why the problem does not present itself with Content-Type set to "text/html"