Is it at all possible to download a file upon an ajax request?
Does it matter if it's same domain / cross domain?
I know it can be done upon redirecting the browser to a URL and setting relevant headers, but was wondering if it can be done when doing an ajax request.
I'm POSTing JSON as the Request Payload to a URL and based on the content of the JSON, I want to send back a specific file.
client.post(url, body: request, headers:{"Content-Type":"application/json"}).then((res) {
if (res.statusCode == 200) {
if ("application/json" == res.headers["content-type"]) {
// parse JSON here
} else {
// download the content if Content-Disposition is set
}
}
}).whenComplete(() {
client.close();
}).catchError((exception, stacktrace) {
print(exception);
print(stacktrace);
showErrorMessage("An Error Occurred");
});
I can see the the correct headers coming back for downloading a PDF, but it's not doing anything if I receive these headers via an AJAX response.
Update - clarifying:
If you click this link, it will do a GET request to Github and download the file: https://github.com/dartsim/dart/archive/master.zip
I'm trying to download the file using a POST request via Dart's BrowserClient.post.
Related
I'm using fetch to return a JSON payload to a React SPA. My web server backend is ASP.NET Core 2.0. I recently updated to ASP.NET Core 2.0 and for the life of me can't figure out why IE no longer works with the web application.
The fetch is pretty straight forward.
fetch(getApiPath() + url, {
credentials: 'include'
})
.then(function(response){
if (response.status === 401 && history) {
history.push("/login")
throw new Error('Redirecting to login');
} else if (response.status === 200) {
return response.json();
} else {
throw new Error(response.statusText);
}
})
.then(success)
.catch(function(e) {
console.log(e)
});
The server end is also pretty straight forward.
[Authorize]
[Route("/dashboard")]
public object Index()
{
Log.Debug("Index");
return new { dashboard = _dashboard, authenticated = HttpContext.User.Identity.IsAuthenticated };
}
The problem manifests itself in a "Invalid Character" error in IE. This works fine in Chrome and Firefox. When looking at the response body, the IE response, is in fact an invalid character while in Chrome, it is the JSON payload.
I'm a little unsure where to even start looking into why IE wouldn't receive or parse the HTTP response correctly. Any ideas?
EDIT:
Making a cross-origin request from a Webpack Dev Server running on port 10000 to a local ASP.NET Core app running on 10001. When packaged for deployment, both the React App and the ASP.NET Core App run on 10000.
Headers between the two requests.
IE Request
IE Response
Chrome
Updated the endpoint to return an IActionResult and explicitly returning JSON. Same result. I've also realized it doesn't work in Edge either.
[Authorize]
[Route("/dashboard")]
public IActionResult Index()
{
return Json(
new { dashboard = _dashboard, authenticated = HttpContext.User.Identity.IsAuthenticated }
);
}
Without additional info I suspect the issue is related to ASP.Net's content negotiation and the fact your method return type is object. Don't use object, this is not Java :))
Before anything else, make sure fetch is sending an Accept: application/json header in IE.
I would also recommend for you to change the return type to IActionResult (or JSONResult if you want to force JSON) for your controller methods.
After setting up Amazon API Gateway CORS as instructed, I still get the following error when send an Ajax POST request.
XMLHttpRequest cannot load https://-------.execute-api.us-west-2.amazonaws.com/--------. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://------.s3-website-us-west-2.amazonaws.com' is therefore not allowed access. The response had HTTP status code 400.
I'm using Amazon S3 to host the website, which does not support web script so I can't use python or php to fix this.
I'd really appreciate any help.
Could it be that you're using Lambda-proxy integration and your Lambda is not returning those headers? If that's the case, you have to add those headers yourself.
This is how I use to create the response that I return using callback(null, response).
function createResponse(statusCode, body) {
const headers = {
'Access-Control-Allow-Origin': '*',
}
return {
headers,
statusCode,
body: body ? JSON.stringify(body) : undefined,
}
}
I am using a combination of Flask and Javascript. After user input from a web page I send a JSON object back to the Flask server. ie:
var xhr = new XMLHttpRequest();
xhr.open('POST', '/completed/');
xhr.setRequestHeader('Content-Type', 'application/json');
var stringifiedObject = dataResultToJSON(data);
xhr.send(stringifiedObject);
Then in Flask:
#main_view.route('/completed/', methods=['POST'])
def completed():
if (request.headers['Content-Type'].startswith('application/json')):
#do stuff here
return redirect(url_for("main_view.home"))
#main_view.route('/')
def home():
logger.debug(">>home")
return render_template('home.html')
When flask redirects to 'home' asfter the Ajax POST I get the following console output:
DEBUG:myapp:>>home
INFO:werkzeug:127.0.0.1 - - [24/Apr/2016 20:13:15] "GET / HTTP/1.1" 200 -
INFO:werkzeug:127.0.0.1 - - [24/Apr/2016 20:13:15] "GET /%3C!DOCTYPE%20html%3E%3C!-- (... entire web page html)
The odd thing is the second INFO statement above - I don't get this line printed when I redirect to home from anywhere else - only occurs when I redirect from the 'completed' POST method. Werkzeug logs the entire home.html web page html and I get an error in the web client:
NetworkError: 404 NOT FOUND - http://127.0.0.1:5000/%3C!DOCTYPE%20html%3E%3C!-- (... entire web page html)
I also added code=307 to the redirect as per here: Make a POST request while redirecting in flask but still got the same 404 error.
I am stuck as to how to get around this.
I think your problem is that you're POSTing data as an AJAX request (i.e. not a browser navigation, but programatically from your client). It doesn't really make much sense to tell your AJAX client to redirect after the POST completes.
You're then trying to tell the client to redirect...but the redirect request is being returned to the XMLHttpRequest.
I'm not 100% sure what you want to happen, but you'd probably be better off using a regular form post if you want the client to redirect once you've posted the data.
I believe what you're trying to do is better illustrated by the answer to this question:
How to manage a redirect request after a jQuery Ajax call
I got this working following the comment and answer above. Specifically I did:
def completed():
#other code here
return url_for("main_view.home")
and in JS:
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
var OK = 200;
if (xhr.status === OK) {
window.location.href = xhr.responseText;
}
else {
console.log ('Error: ' + xhr.status);
}
}
};
Hello i've got a problem with ajax json request. Im always getting an error, even if the requests are succeeded. At the moment i have this code:
function sumbitLoginForm(user, pass) {
if (user.trim() == '' || pass.trim() == '') {
alert("You must enter username and password!");
} else {
$.ajax({
type : 'POST',
url : 'https://url.php',
dataType : 'json',
data : {
userlogin : user,
userpass : pass
},
contentType: "application/json;",
success : function(data) {
$("#images").html("uspeshno");
},
error : function(data) {
$("#images").html("greshka");
}
});
}
return false;
}
$(document).ready(function() {
clearPageInputs();
$("#submitButton").click(function() {
sumbitLoginForm($("#username").val(), $("#password").val());
});
});
Im always getting an error , no matter what username and password i type . But the status of request is changing , if i type correct user and pass i get status 302 Moved temporarly , but when i type wrong user or pass i get status 200 OK . What am i doing wrong ?
PRG Pattern and Ajax
It looks like your server returns a HTTP 200 status code when the userid and password will not validate. This is proper behavior, as HTTP error codes not meant for application errors, but for HTTP protocol errors.
When the userid and password are matched succesfully, you are redirected to another page. This is also normal behavior, e.g. to prevent other people to re-use your login credentials using the back key.
This is called the Post/Redirect/Get pattern.
See: http://en.wikipedia.org/wiki/Post/Redirect/Get
The problem is that the PRG pattern does not play nice with Ajax applications. The redirect should be handled by the browser. It is therefore transparent for the jQuery code. The Ajax html response will be the page that is mentioned in the Location header of the 302. Your Ajax application will not be able to see that it is being redirected. So your are stuck.
In one of my projects I solved this on the server side. If I detected an Ajax call, I would not send a redirect but a normal 200 response. This only works if you have access to the server code.
If you cannot change the redirect for your Ajax calls, then you can parse the response headers or the html to see if you were being redirected and act accordingly. Probably the login will set a cookie, so you might try and look for the presence of that cookie.
I'm working on a playbook app with webworks sdk.
I'm trying to make an http request (method: post) by sending AND recieving data.
I can get the response from server, but the server can't get the $POST data, when I try to display $_POST['apiKey'], nothing apears, I checked my code 100 times, checked my config.xml for uri, can't find the error.
TL;DR: can't send but can receive data.
My PHP Server code:
echo "passed key is: ".$_POST["apiKey"]; // Nothing apears
echo "<br>";
if(md5($_SESSION['private_key'])===$_POST["apiKey"]){
}
else{
echo "Invalid API Key"; // Always getting this response on client app
exit();
}
?>
My JS Client code:
function httpRequest(){
var key="a984a4474cff54d8468a296edf3af65b";
document.getElementById("status").innerHTML="Reaching server...";
//////////////////////////////////////
var xdr = getXDomainRequest();
xdr.onload = function() {
document.getElementById("status").innerHTML=xdr.responseText;
}
xdr.open("POST", "http://mydomain/index.php");
xdr.send("apiKey="+key);
}
Solved:
When using POST method you should define the request header:
xdr.open("POST", "http://mydomain.com/index.php");
xdr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); // with this line
xdr.send("apiKey="+key);
Solved: When using POST method you should define the request header:
xdr.open("POST", "http://mydomain.com/index.php");
xdr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); // with this line
xdr.send("apiKey="+key);