My goal is to print a string from a rendered html page.
I'm using the code below to fetch body content from a url:
var proxy = "http://myproxyname.pythonanywhere.com/response?userinput=google"
$.ajax({
url: proxy,
dataType: 'text',
success: function(data) {
$('#display').text(data);
}
})
}
I'm using this because the API i'm working with require Allow cross origin, actually, I setup a little flask app that do the job for me. I'm able to print html of some urls I tested with this function so it's working but for the one I'm using it's 200 OK but empty response.
Can someone explain why I'm not receiving the html content? Is there a special parameters with Jquery? Should I enable cross-origin in my flask app?
My last question is how to make the request but telling Javascript not to take into account headers?
Update:
When I make the request manually from the console I get a response but unable to print it on the page cause = other. When I click on the button to make the request it throw cause = JS and there's no response inside.
Update 2:
When I receive a valid response in the console, I only see this changes in request headers:
Pragma "no-cache"
Cache-Control "no-cache"
There's a way I can add it directly to the JS code?
Update 3:
My proxy code using Python (Flask):
#app.route('/response')
def response():
url = 'http://longstringurlapi.com'
data = str(request.args.get( "userinput" , None ))
jsoninput = json.dumps(data)
r = requests.post(url ,data=jsoninput)
response = r.text
return render_template('results.html', response=response, data=data)
#app.route('/')
def home():
return render_template('index.html')
Related
I'm writing a full stack app. I have a python backend using flask that sends a file and a Vue client that receives. Its been working fine up until the point when I try to send the filename over using a Content-Disposition header.
On the backend I've tried:
return send_file(base_path + filename, as_attachment=True, download_name=filename)
And to set the headers manually,
response = make_response(send_file(base_path + filename))
response.headers['Content-Disposition'] = f"attachment; filename=\"{filename}\""
return response
I've also tried to put in headers that would not be blocked by CORS just to see if the request would receive the header but to no avail,
response = make_response(send_file(base_path + filename))
response.headers['Content-Type'] = "sample/info"
return response
I'm printing the header to the console by doing
fetch('http://localhost:4999/rdownload/' + this.$route.params.id, {
method: 'GET'
}).then(res =\> {
if (res.status == '500') { }
console.log(res.headers)
//const header = res.headers.get('Content-Disposition');
//console.log(header)
res.blob().then((blob) => {
/* ... */
})
})
Any help would be appreciated! Thanks :)
Research
In the interest of logging the solution I found and helping out anyone in the future who may be interested in knowing the answer here's what I discovered:
There is a restriction to access response headers when you are using Fetch API over CORS.
https://stackoverflow.com/a/44816592/20342081
So, no matter what using the JS fetch-api you will be unable to access all headers (outside of Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, and Pragma) unless you expose them by specifying them in a request header. That would look something like this:
fetch('https://myrequest/requestend/', {
headers: {
'Access-Control-Expose-Headers': 'Content-Disposition'
}
})
When a cross-origin source accesses your API you will have to expose the header from the back end as well. https://stackoverflow.com/a/66291644/20342081
I was also confused about how the differences between Access-Control-Expose-Headers and Access-Control-Allow-Headers. In my case the solution was use "expose headers" on both the frontend and the backend (and allow wouldn't work). However, Allow has its own applications which I have yet to understand fully. For those endeavoring check out: https://stackoverflow.com/a/28108431/20342081
Solution
I implemented these things in my code by doing:
class RequestResult(Resource):
def get(self, index):
base_path = f"Requests/{index}/"
filename = os.listdir(base_path)[0]
response = make_response(send_file(base_path + filename, as_attachment=True, download_name=filename))
response.headers['Access-Control-Expose-Headers'] = "Content-Disposition"
return response
And on the front end exposing the header as well on the fetch request:
fetch('http://localhost:4999/rdownload/' + this.$route.params.id, {
method: 'GET',
mode: 'cors',
headers: {
'Access-Control-Expose-Headers': 'Content-Disposition'
}
})
I hope this is helpful for the next 5 people who open this in the next 10 years!
Just started learning HTTP, trying to make a simple client-to-server request to work in tornado. Here is my javascript function trigged by a button click:
function funcOnClick(){
$.ajax({
url: "http://localhost:8889/madTest",
type: "GET",
success: function(result){alert('success')},
error: function(error){console.log(error)}
})
}
And here is my server:
import tornado.ioloop
import tornado.web
import json
class MainHandler(tornado.web.RequestHandler):
def get(self):
print('got the GET request')
self.write('abc')
def make_app():
return tornado.web.Application([
(r"/madTest", MainHandler),
])
if __name__ == "__main__":
app = make_app()
app.listen(8889)
print('server started, listening to 8889 ...')
tornado.ioloop.IOLoop.current().start()
On clicking the button, I see "got the GET request" printed, so the server must have gotten the request. However, I got this error on console:
Any suggestions? Thanks!
The error message occurs when your JS or HTML page is served from a different domain and you're trying to make an AJAX request to a different domain. This is called CORS. For security reasons, web browsers restrict cross-domain AJAX requests unless allowed by the server.
To be able to make cross origin AJAX requests, you'll need to set a header called Access-Control-Allow-Origin in your handler's response.
You can do this in the prepare method of your handler:
class MainHandler(...):
def prepare(self):
self.set_header('Access-Control-Allow-Origin', '*')
# the wildcard - '*' - allows CORS from any domain
# you should probably change it to your frontend
# domain name if you wan to restrict CORS to a single domain.
# see Mozilla docs for more info
Using angular v1.3.1 i got a singular the following problem trying to implement a facade for making http request to a REST + JSON interface in the backend of the web app.
I got something like this in the code:
findSomething(value: number): ng.IPromise<api.DrugIndication[]> {
const getParams = { 'param' : 'value' };
const config:ng.IRequestShortcutConfig = {
headers: {
"Content-Type" : "application/json"
},
data: getParams
}
return this.$http.get(url,config);
}
And when the times comes to invoke it, i got an 400 Bad Request (btw: Great name for a band!) because the backend (made with Play for Scala) rejects the request inmediately. So making an inspection in the request i see that no data is being send in the body of the request/message.
So how i can send some data in the body of and HTTP Get request using angular "$http.get"?
Additional info: This doesn't happen if i the make request using the curl command from an ubuntu shell. So probably is an problem between Chrome and angular.js
If you inspect the network tab in chrome development tools you will see that this is a pre-flight OPTIONS request (Cross-Origin Resource Sharing (CORS)).
You have two ways to solve this.
Client side (this requires that your server does not require the application/json value)
GET, POST, HEAD methods only
Only browser set headers plus these
Content-Type only with:
application/x-www-form-urlencoded
multipart/form-data
text/plain
Server side
Set something like this as a middleware on your server framework:
if r.Method == "OPTIONS" {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type,Authorization")
w.Header().Set("Access-Control-Max-Age", "86400") // firefox: max 24h, chrome 10min
return
}
For your specific framework this should work
Using config.data will send the data in the request body, use
config.params = getParams
This is from the documentation :
params – {Object.} – Map of strings or objects which will be serialized with the paramSerializer and appended as GET parameters
I have a web app using Python Django and Dojo framework.
I wanna send a PUT request from Dojo (using dojo/request) to server Django but when server receives a request, the data within are empty and validate Invalid.
BUT when I change method from PUT to POST, it's work correctly.
Here is my code:
_save: function(data){
var idForm = "editForm" + this.id;
var value = dijit.byId(idForm).get('value');
console.log(value);
request.put("/api/guestbook/"+this.bookName+"/greeting/"+this.id+"/", {
data: {
book_name: this.bookName,
message: value.message
},
headers: { "X-CSRFToken": _cookie('csrftoken') }
}).then(lang.hitch(this, function(text){
}));
},
And in Django:
def put(self, request, *args, **kwargs):
form = self.get_form(self.form_class)
logging.warning(form)
logging.warning(request.PUT)
if form.is_valid():
logging.warning("This form is VALID")
else:
logging.warning("This form is INVALID!!!")
Anyone can help me?
Thanks for help!
I found the way to receive PUT method below:
def put(self, request, *args, **kwargs):
request.PUT = QueryDict(request.body)
form = self.form_class(request.PUT)
if form.is_valid():
logging.warning("This form is VALID")
else:
logging.warning("This form is INVALID")
This is ok :)
Thanks all!
I'm guessing from your X-CSRFToken header that you are doing cross domain requests, i.e. CORS.
If you look in your browser's console, you'll probably see an OPTIONS request being sent to the server. This is called a "preflight request", and your server needs to respond with CORS headers telling the browser that it's okay to make the cross domain PUT request.
In your case, you want the server to respond with headers similar to:
Access-Control-Allow-Origin: http://your-site-hostname-and-port
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-CSRFToken
Simple POST requests do not need the preflight OPTIONS request, that's probably why it works. A pretty good tutorial on html5rocks here.
I am a newbie to Bottle and sort of to Python as well and I am trying create an app whenever I click a button, an AJAX is fired and POST a json to server and store it using SQLite.
However, at current stage, I am trying to figure out how do I successfully received the data in the server.
On the client side,
I have the following send_data function written in JavaScript.
function send_data(feedback) {
$.ajax({
url: "/feedback",
type: "POST",
data: JSON.stringify(feedback),
contentType: "application/json",
success: function() {
alert("Feedback successfully stored in the server!");
},
error: function() {
alert("Feedback failed to store back in the server!");
},
}
The passed in parameter feedback looks something like {"id1": 1, "id2": 2}.
On the server side, I have a feedback.py file and the code is
from bottle import request, route, run
#route('/feedback', method='POST')
def feedback():
comments = request.json
print comments
run(host='localhost', port=8080)
Right now, I just want to check if I have received the data successful. But everytime, when I click that botton, I receive the following error
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/feedback. This can be fixed by moving the resource to the same domain or enabling CORS.
OPTIONS http://localhost:8080/feedback [HTTP/1.0 405 Method Not Allowed 2ms]
I am not sure if it's because I am not using the element <form>. That botton is technically just an image. Every time I click that image, send_data() function is fired.
Anyone can help? I really appreciate it. Thank you!
Cross Origins Requests are restricted as a security measure by the browser. It is possible to overcome that by setting an Access-Control-Allow-Origin header. You can can use bottle-cors or create a decorator like the following on your server code (Python/bottle):
def enable_cors(fn):
def _enable_cors(*args, **kwargs):
response.headers['Access-Control-Allow-Origin'] = '*'
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, OPTIONS'
response.headers['Access-Control-Allow-Headers'] = 'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token'
if request.method != 'OPTIONS':
# actual request; reply with the actual response
return fn(*args, **kwargs)
return _enable_cors
and then with your example:
from bottle import request, route, run
#enable_cors
#route('/feedback', method='POST')
def feedback():
comments = request.json
print comments
run(host='localhost', port=8080)
Note that it's best to allow specific origins instead of using *.
You can read more about Cross-Origin Resource Sharing (CORS) here
You can make this work by disabling the Cross-origin restrictions.
On safari, open the Develop panel, and check disable cross-origin restrictions, or use a browser like Firefox.