Executing a post request from a flask route to a remote service - python

I am encountering some issues to create and execute a post request from one of my flask #app.route. The idea would be to validate and process the data received from a web form by the server, then to call a remote service with this data as a post parameter and finally to be redirected to a new page indicated by this remote service. This is a simplified skeleton :
import requests
#app.route('/test', methods=['POST'])
url = 'http://exemple.com'
headers = {'Content-type': 'text/html; charset=UTF-8'}
response = requests.post(url, data=data, headers=headers)
return x
Any hint about how am I supposed to redirect the user to the remote service using a post request (user that will then again be redirected by the remote service to another page)?
Thank you in advance.

You don't need to redirect user to the remote server. Just send POST request inside this route function and either wait for the response from that server and then render some template to user with received response or send POST request to the desired server in another thread if you know that response can take a lot of time (in this case you can render some page immediately where would be something like "Processing your request" message). In the second case (in case of sending POST request in a different thread) you can show result of the request after reloading page retrieving it from some shared object in main thread that can be modified from the thread you use to send POST request from.
1) Sending request in the route function:
#app.route('/test/', methods=['POST'])
def test():
url = 'http://exemple.com'
headers = {'Content-type': 'text/html; charset=UTF-8'}
response = requests.post(url, data=data, headers=headers)
# wait for the response. it should not be higher
# than keep alive time for TCP connection
# render template or redirect to some url:
# return redirect("some_url")
return render_template("some_page.html", message=str(response.text)) # or response.json()
2) Sending POST request in a different thread (you can use this option if you know that response time is much higher than TCP keep alive time):
from threading import Thread
from flask import Flask, redirect
app = Flask(__name__)
shared_var = None
req_counter = 0
def send_post_req(url, data):
global shared_var
headers = {'Content-type': 'text/html; charset=UTF-8'}
response = requests.post(url, data=data, headers=headers)
shared_var = response.text # or response.json() - it's up to you
#app.route('/test/', methods=['POST'])
def test():
global req_counter
url = 'http://exemple.com'
data = "some data"
if req_counter == 0:
t = Thread(target=send_post_req, args=(url, data))
t.setDaemon(True)
t.start()
req_counter = 1 # use req_counter if you want to send request only one time
if shared_var:
# render some page or redirect to desired url using:
# return redirect(url_for('some_route_name'))
# or
# return redirect("some_url")
return render_template("some_page.html", message=str(shared_var))
return render_template("some_page.html", message="Your request is being processed")
or something like that.
Hope my explanation is clear.
Also you can pay attention to asyncio and Sanic to use asynchronous approach.

Send post request with your user data. Then parse the response to get your link.
import requests
from flask import Flask, redirect
app = Flask(__name__)
#app.route('/test', methods=['POST'])
def test():
# Get your post data from your client request and process it
# Send POST request
r = requests.post("http://example.com", data={your_data})
res_var = response.text #TEXT/HTML response
res_code = response.status_code, response.reason #HTTP
new_destination = '' # get your new link from res_var
Once you have your redirect link... simply use:
return redirect(new_destination, code=302)

Related

How can I make post requests with querystrings using sessions in Python?

i'm using requests module and i'm interested in sending a post request with querystrings using sessions, how can I do that? I haven't found anything related with request.Sessions and querystrings
with Sessions (it returns me a http 500 response code)
response = self.session.post(self.url, data = payload, headers = self.headers, params = querystring)
without Sessions ( it works fine)
response = requests.request("POST", self.url, json=payload, headers=self.headers, params=querystring)
Maybe you can provide the url and a little bit more code.
In the session example you pass data=payload.
In the second example json=payload.
Did you create the session correctly?

Making a successful Python HTTP POST Request

I am trying to write a python script that will make a request to a desktop application listening to 8080 port. The below is the code that I use to make the request.
import requests
payload = {"url":"abcdefghiklmnopqrstuvwxyz=",
"password":"qertyuioplkjhgfdsazxvnm=",
"token":"abcdefghijklmn1254786=="}
headers = {'Content-Type':'application/json'}
r = requests.post('http://localhost:9015/login',params = payload, headers=headers)
response = requests.get("http://localhost:9015/login")
print(r.status_code)
After making the request, I get a response code of 401.
However, when I try the same using the Postman app, I get a successful response. The following are the details I give in Postman:
URL: http://localhost:9015/login
METHOD : POST
Headers: Content-Type:application/json
Body: {"url":"abcdefghiklmnopqrstuvwxyz=",
"password":"qertyuioplkjhgfdsazxvnm=",
"token":"abcdefghijklmn1254786=="}
Can I get some suggestions on where I am going wrong with my python script?
You pass params, when you should pass data, or, even better, json for setting Content-Type automatically. So, it should be:
import json
r = requests.post('http://localhost:9015/login', data=json.dumps(payload), headers=headers)
or
r = requests.post('http://localhost:9015/login', json=payload)
(params adds key-value pairs to query parameters in the url)

Send POST request from Tornado to Django rest framework, real time chat application

I'm working on a chat app for mobile that needs to handle 10k+ messages/s.
I want to save every message to database by sending post requests from tornado to django rest.
I don't know which is the best way to write my post request not to slow down the server.
This is my function:
def SaveToDatabase(endpoint, data):
#data= {"user_id": msg['username'], "room_id": 1, "message": msg['payload']}
req = urllib2.Request(endpoint)
req.add_header('Content-Type', 'application/json')
urllib2.urlopen(req, json.dumps(data))
Thanks!
Tornado is an asynchronous server, so you should send that post request in asynchronous way also. urllib2 will block whole worker waiting for response, that worker won't take any other requests until post is done. You should use httpclient from tornado:
request = httpclient.HTTPRequest(endpoint, body=json.dumps(data), method="POST", headers={"content-type": "application/json"})
response = yield http_client.fetch(request)
print response
All that code should be inside coroutine. You can also use AsyncHTTPClient that will call your callback when request is finished instead of creating proper coroutine for that.

Reading POST body with bottle.py

I am having trouble reading a POST request with bottle.py.
The request sent has some text in its body. You can see how it's made here on line 29: https://github.com/kinetica/tries-on.js/blob/master/lib/game.js.
You can also see how it's read on a node-based client here on line 4: https://github.com/kinetica/tries-on.js/blob/master/masterClient.js.
However, I haven't been able to mimic this behavior on my bottle.py-based client. The docs say that I can read the raw body with a file-like object, but I can't get the data neither using a for loop on request.body, nor using request.body's readlines method.
I'm handling the request in a function decorated with #route('/', method='POST'), and requests arrive correctly.
Thanks in advance.
EDIT:
The complete script is:
from bottle import route, run, request
#route('/', method='POST')
def index():
for l in request.body:
print l
print request.body.readlines()
run(host='localhost', port=8080, debug=True)
Did you try simple postdata = request.body.read() ?
Following example shows reading posted data in raw format using request.body.read()
It also prints to the log file (not to the client) raw content of body.
To show accessing of form properties, I added returning "name" and "surname" to the client.
For testing, I used curl client from command line:
$ curl -X POST -F name=jan -F surname=vlcinsky http://localhost:8080
The code which works for me:
from bottle import run, request, post
#post('/')
def index():
postdata = request.body.read()
print postdata #this goes to log file only, not to client
name = request.forms.get("name")
surname = request.forms.get("surname")
return "Hi {name} {surname}".format(name=name, surname=surname)
run(host='localhost', port=8080, debug=True)
Simple script for processing POSTed data. POSTed data are written in a terminal and returned to the client:
from bottle import get, post, run, request
import sys
#get('/api')
def hello():
return "This is api page for processing POSTed messages"
#post('/api')
def api():
print(request.body.getvalue().decode('utf-8'), file=sys.stdout)
return request.body
run(host='localhost', port=8080, debug=True)
Script for POSTing json data to the script above:
import requests
payload = "{\"name\":\"John\",\"age\":30,\"cars\":[ \"Ford\", \"BMW\",\"Fiat\"]}"
url = "localhost:8080/api"
headers = {
'content-type': "application/json",
'cache-control': "no-cache"
}
response = requests.request("POST", url, data=payload, headers=headers)
print(response.text)

Web proxy in python/django?

I need to have a proxy that acts as an intermediary to fetch images. An example would be, my server requests domain1.com/?url=domain2.com/image.png and domain1.com server will respond with the data at domain2.com/image.png via domain1.com server.
Essentially I want to pass to the proxy the URL I want fetched, and have the proxy server respond with that resource.
Any suggestions on where to start on this?
I need something very easy to use or implement as I'm very much a beginner at all of this.
Most solutions I have found in python and/or django have the proxy acts as a "translater" i.e. domain1.com/image.png translates to domain2.com/image.png, which is obviously not the same.
I currently have the following code, but fetching images results in garbled data:
import httplib2
from django.conf.urls.defaults import *
from django.http import HttpResponse
def proxy(request, url):
conn = httplib2.Http()
if request.method == "GET":
url = request.GET['url']
resp, content = conn.request(url, request.method)
return HttpResponse(content)
Old question but for future googlers, I think this is what you want:
# proxies the google logo
def test(request):
url = "http://www.google.com/logos/classicplus.png"
req = urllib2.Request(url)
response = urllib2.urlopen(req)
return HttpResponse(response.read(), mimetype="image/png")
A very simple Django proxy view with requests and StreamingHttpResponse:
import requests
from django.http import StreamingHttpResponse
def my_proxy_view(request):
url = request.GET['url']
response = requests.get(url, stream=True)
return StreamingHttpResponse(
response.raw,
content_type=response.headers.get('content-type'),
status=response.status_code,
reason=response.reason)
The advantage of this approach is that you don't need to load the complete file in memory before streaming the content to the client.
As you can see, it forwards some response headers. Depending on your needs, you may want to forward the request headers as well; for example:
response = requests.get(url, stream=True,
headers={'user-agent': request.headers.get('user-agent')})
If you need something more complete than my previous answer, you can use this class:
import requests
from django.http import StreamingHttpResponse
class ProxyHttpResponse(StreamingHttpResponse):
def __init__(self, url, headers=None, **kwargs):
upstream = requests.get(url, stream=True, headers=headers)
kwargs.setdefault('content_type', upstream.headers.get('content-type'))
kwargs.setdefault('status', upstream.status_code)
kwargs.setdefault('reason', upstream.reason)
super().__init__(upstream.raw, **kwargs)
for name, value in upstream.headers.items():
self[name] = value
You can use this class like so:
def my_proxy_view(request):
url = request.GET['url']
return ProxyHttpResponse(url, headers=request.headers)
The advantage of this version is that you can reuse it in multiple views. Also, it forwards all headers, and you can easily extend it to add or exclude some other headers.
If the file you're fetching and returning is an image, you'll need to change the mimetype of your HttpResponse Object.
Use mechanize, it allow you to choose a proxy and act like a browser, making it easy to change the user agent, to go back and forth in the history and to handle authentification or cookies.

Categories

Resources