In javascript how do you open a file from the server? - javascript

Im working in an application that uses java + spring on the server side aswell as extdirectspring. On the client side it uses extjs/javascript.
I want to poke a method on the serverside and retrieve a file from the database. If the file doesn't exist then I'd like to display an error in some way.
The attempt to retrieve the file and the check it exists need to happen in the same call - the file could be deleted in between calls.
The way I can see people have done it in the current application is using spring controllers + request mappings and a window.open("someUrl/filename.blah"); with the server returning the file from the mapped method.
This doesnt seem to let you handle the case where the file doesn't exist though.
Ideally I'd just like to send some json back from the server which has the file data (possibly null) and sucess/failure. When I get the response I can then either show some information about the failure or open the file. Unfortunately I can't observe the current failure mode because something somewhere is caching the files - if I delete them from the database then they appear to still exist and you can still download them!
By 'open' I mean show the standard 'what do you want to do with this file open/save' dialog. I'm not trying to parse the file or do anything with it - I just want to serve it up to the browser/user.
Is there a way to do that without using a url and window.open? Eg some method that takes a blob of data and a file name or similar?
Update
The transfer of the data/json isn't the problem I'm trying to solve.
As I'm using extdirect I'll probably just do it like this:
public class SomeClass
{
#ExtDirectMethod
public AFile getFile(Long id) throws Exception
{
//do stuff
}
}
Then on the clientside you just do:
someClass.getFile(id, function(file){
if(file.found){
SomeHowGiveThisToTheUser(file.name,file.data); ????
return;
}
ReportCouldntFind(file.name);
});
The bit I dont know how to do is the give the file to the user.
Further update
I dont think it's possible to do this without blob urls or data uri's. Both of these are mentioned in this post. I haven't tried them out as we are having to support a browser that is too old for both techniques.

You are wanting to do some standard Ajax (Assuming you have jQuery available).
Something like:
$.getJSON( url, function( data ) {
if (data.success){
} else {
}
});
And on the server side, add code to return the expected JSON.
In extJS:
Ext.Ajax.request({
url : url,
method: 'GET',
headers: { 'Content-Type': 'application/json' },
params : params,
success: function (response) {
var jsonResp = Ext.util.JSON.decode(response.responseText);
if (response.success){
// do success stuff, like using response.fileData
} else {
// do fail stuff
}
failure: function (response) {
var jsonResp = Ext.util.JSON.decode(response.responseText);
// etc.
});
On the server in a Java servlet you could something like this (assumes apache commons file util):
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
InputStream in = new URL( "http://remote.file.url" ).openStream();
IOUtils.copy(in, response.getOutputStream());
}
Probably a more spring specific way to do it, but that gives you an idea.
For your case, you want to wrap the file contents in a JSON object that includes the success proeprty. For that, use the Java JSON jar: http://json.org/java/
Update: Finally understand what you are asking.
It finally occurred to me that you are asking how to handle the actual download.
There's a couple ways these days.
Take a look at this SO answer, this is using an iFrame: Download File Using Javascript/jQuery
There are also several fancy downloader components, including several for jQuery.
So you would do a two part process: check for the file availability using a standard ajax call, and then if response.success, use the downloader to serve the file to the user.

Related

In Javascript how can I redirect an Ajax response in window location

I currently have the following working piece of code (angular but applies to any JS framework):
var url = '/endpoint/to/my/file';
$http({
method: 'GET',
url: url
})
.success(function(jdata) {
window.location = url;
})
.error(function(je){
// display errors on page
});
The above is called after a form was completed and the user has clicked on "submit" (the real situation is a bit more complex than this but it is the same idea). I do the form check asynchronously, so there's no page reload.
If the request is successful, returns a binary (a pdf file), if not succesful, the request returns a 400 BadRequest with errors formatted in JS. So what I do is, if successful, I redirect to the same url to have the PDF otherwise I get the JSON error object and do something with it.
How can I refrain from making two requests if the requests is successful?
Note1: on the backend side I would like to keep only one route that does everything, check + return PDF
Note2: the current situation is pretty neat in my opinion, since I have an asynchronous form check and if successful the file downloads directly in the browser since I have "CONTENT-DISPOSITION" -> "attachment" in the HTTP header of the successful response
Update: additional information about the architecture as requested by Emile:
In my use case I have one endpoint that checks inputs (and other external requirements). For security reasons I cannot output the PDF if all requirements are not satisfied so I have to do the check prior to delivering the file ( the file is automatically generated) anyway. So having two endpoints would just be redundant and add some unnecessary complexity.
While writing I think an alternative solution could be to pass an argument on the endpoint while doing the check, so that if successful, it stops and does not generate the PDF, and then redirect to the same endpoint without the flag which will output the PDF.
So I do the check twice but only load (and generate - which is resource intensive) the file only once and I have only one endpoint...
Here's the adapted code:
var url = '/endpoint/to/my/file';
$http({
method: 'GET',
url: url+'?check'
})
.success(function(jdata) {
window.location = url;
})
.error(function(je){
// display errors on page
});
On the backend side (I use Play framework/Scala)
def myendpoint(onlyDoCheck: Boolean = false) = Action{implicit request =>
myForm.bindFromRequest.fold(
e => BadRequest(myErrors),
v => if(onlyDoCheck) Ok(simpleOkResponse) else Ok(doComputationgeneratefileandoutputfile)
)
}
The real deal
The best you could do is split your endpoint.
One for the form and the convenience of having errors without refresh.
Then, on success, redirect to your other endpoint which only downloads the file.
If the file was on the disk and wasn't auto-generated and required to be authenticated to be downloaded, you could hide the file behind a normal endpoint, do the checks, and return the file using X-Accel-Redirect header with nginx or X-Sendfile using apache.
The hack
Disclaimer: This is more of a hack than the best solution. As mention by #Iceman, Safari, IE, Safari-iOS, Opera-mini and some such browsers don't support this particular spec.
In your server-side endpoint, if the file is available without errors, you can set the header to the content-type of the file (like 'application/pdf') so the download will starts automatically.
If there are errors, don't set the header and return a json of the errors to inform the user through javascript.
Since we don't know what's behind, here's a python (Django) example:
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename=your_filename.pdf'
response.write(repport.printReport(participantId))
return response
You can handle the response in the ajax success callback:
$.ajax({
url: 'endpoint.php',
success: function(data) {
var blob = new Blob([data]);
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = "filename.pdf";
link.click();
}
});
You could also try the jQuery fileDownload plugin mentioned in this answer.

How to consume a JSON endpoint?

So I have been supplied an URL for an "exposed JSON endpoint" similar to one found here-only difference is the functions are different. First of all what does this mean("exposed JSON endpoint") ? And how do I call this web service ? I have used web services like the Google Maps with C# where I would download and parse the XML from URL and use the data. But with this, I have no idea how to use the service. (any code in Javascript, C#, Java is fine). Thanks for any help !
An "exposed JSON endpoint" is a publicly available URL (sometimes with query or path parameters added by you) which you can send an HTTP request to and it will return JSON from the remote server that is related to the request you sent.
You then parse the returned JSON (into the structure of whatever programming language you are using) so you can then use the returned data in your own code.
Maybe you can try something like this:
WebClient client = new WebClient();
Stream stream = client.OpenRead("Endpoint");
StreamReader reader = new StreamReader(stream);
Newtonsoft.Json.Linq.JObject jObject = Newtonsoft.Json.Linq.JObject.Parse(reader.ReadLine());
As the service end point states:
You need to include the following element in your page
<script src="http://orc.csres.utexas.edu/orchard/json/compiler?js"/></script>
Then you call the service using something like this
try {
compilerService.compile(
{
devKey : "key",
program : "program"
},
function(returnValue) {
// it worked do something with returnValue
console.log(returnValue);
},
function(response, status, exception) {
// something went wrong
console.log(response);
console.log(status);
console.log(exception);
}
);
}
catch (e) {
console.log(e);
}

PUT and POST Request of .save() of Backbonejs model

How to be confirmed whether a backbonejs .save() is sending PUT request ?? I checked my server side, which is working good, there is no problem in server side. But my .save() is not working.
Here is my model of backbone
define(['underscore','backbone'],function(_,Backbone)
{
var my_model = Backbone.Model.extend(
{
urlRoot: "http://localhost/back/server_file.php/number"
});
return my_model;
});
Here is how I am using .save()
var my_data = {
id: data.id,
code: data.code
};
var My_model = new my_model();
My_model.save(my_data,
{
success: function(response)
{
alert('Yes');
},
error: function(response)
{
alert('No');
}
});
I think my .save() is sending POST request to server.
UPDATE
I think I could find out my problem. I am describing that here.
What I would like to do
I would like to send 2 parameters from backbonejs model to server side script (I am using PHP SLIM Framework). Based on those 2 parameters server side script update a record's(2 field of this record match with those 2 parameters ) another field with a static parameter at database.
What backbonejs provide (As I think )
Backbonejs has a model with id as JSON format. Backbonejs sends PUT request to server side script. Server side script just dump (update) the data(which was as JSON format,like a bundle) to the database with matching id. Serer side script would not like to look inside the data.
I am getting (from network tab of firebug) my PUT request URL is like http://localhost/back/server_file.php/number/1 (This is the id) . On the other hand I would like to get URL is like http://localhost/back/server_file.php/number/1 (id the first parameter)/456 (Second parameter).
If I am right, anyone could say how can I implement my plan??
This should work,
My_model.set(my_data);
My_model.save(null, {
wait : true,
url : "http://localhost/back/server_file.php/number/1/456",
success : function(response){
},
error : function(e){
}
});
You can debug the request being sent in network tab of Chrome Developer Tools or you can use a network tool like Fiddler to see all requests.
Refer the attached on where to see the request method being used.

How to send data in request body with a GET when using jQuery $.ajax()

The service API I am consuming has a given GET method that requires the data be sent in the body of the request.
The data required in the body is a list of id's separated by hypen and could potentially be very large and thus it must be sent in the body otherwise it will likely foobar somewhere in the browsers/proxies/webservers etc chain. Note I don't have control over the service or API so please don't make suggestions to change it.
I am using the following jQuery code however observing the request/response in fiddler I can see that the "data" I am sending is ALWAYS converted and appended to the query string despite me setting the "processData" option to false...
$.ajax({
url: "htttp://api.com/entity/list($body)",
type: "GET",
data: "id1-id2-id3",
contentType: "text/plain",
dataType: "json",
processData: false, // avoid the data being parsed to query string params
success: onSuccess,
error: onError
});
Anyone know how I can force the "data" value to be sent in the body of the request?
In general, that's not how systems use GET requests. So, it will be hard to get your libraries to play along. In fact, the spec says that "If the request method is a case-sensitive match for GET or HEAD act as if data is null." So, I think you are out of luck unless the browser you are using doesn't respect that part of the spec.
You can probably setup an endpoint on your own server for a POST ajax request, then redirect that in your server code to a GET request with a body.
If you aren't absolutely tied to GET requests with the body being the data, you have two options.
POST with data: This is probably what you want. If you are passing data along, that probably means you are modifying some model or performing some action on the server. These types of actions are typically done with POST requests.
GET with query string data: You can convert your data to query string parameters and pass them along to the server that way.
url: 'somesite.com/models/thing?ids=1,2,3'
we all know generally that for sending the data according to the http standards we generally use POST request.
But if you really want to use Get for sending the data in your scenario
I would suggest you to use the query-string or query-parameters.
1.GET use of Query string as.
{{url}}admin/recordings/some_id
here the some_id is mendatory parameter to send and can be used and req.params.some_id at server side.
2.GET use of query string as{{url}}admin/recordings?durationExact=34&isFavourite=true
here the durationExact ,isFavourite is optional strings to send and can be used and req.query.durationExact and req.query.isFavourite at server side.
3.GET Sending arrays
{{url}}admin/recordings/sessions/?os["Windows","Linux","Macintosh"]
and you can access those array values at server side like this
let osValues = JSON.parse(req.query.os);
if(osValues.length > 0)
{
for (let i=0; i<osValues.length; i++)
{
console.log(osValues[i])
//do whatever you want to do here
}
}
Just in case somebody ist still coming along this question:
There is a body query object in any request. You do not need to parse it yourself.
E.g. if you want to send an accessToken from a client with GET, you could do it like this:
const request = require('superagent');
request.get(`http://localhost:3000/download?accessToken=${accessToken}`).end((err, res) => {
if (err) throw new Error(err);
console.log(res);
});
The server request object then looks like {request: { ... query: { accessToken: abcfed } ... } }
You know, I have a not so standard way around this. I typically use nextjs. I like to make things restful if at all possible. If I need to make a get request I instead use post and in the body I add a submethod parameter which is GET. At which point my server side handles it. I know it's still a post method technically but this makes the intention clear and I don't need to add any query parameters. Then the get method handles a get request using the data provided in the post method. Hopefully this helps. It's a bit of a side step around proper protocol but it does mean there's no crazy work around and the code on the server side can handle it without any problems. The first thing present in the server side is if(subMethod === "GET"){|DO WHATEVER YOU NEED|}

jQuery Get Request on HTTP URL

i've recently tried to get some Response from an URL using jQuery. Therefore I copied a get request sample of jQuery API Get Request Tutorial into my project and tried to run it, but my debugging messages showed me, that it can't go further. I tried the javascript Ajax Library using a simple request, but it didn't work.
So i'm asking you, if you could help me somehow.
And this is all what i do, but there is no response.
var url = "http://www.google.com";
$.get(url, function(data){
alert("Data Loaded: " + data);
});
Did i probably forgot to include a ajax or jQuery library. For a better understanding, i have c and obj-c experince, this is why i think, that a library is missing.
In each sample there is just a short url like "test.php". Is my complete HTTP url wrong?
Thanks for your answers in advanced.
Br
Nic
I have provided an example scenario to help get you started:
<!-- Include this jQuery library in your HTML somewhere: -->
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js"></script
This is probably best to include inside of an external JS file:
//Listen when a button, with a class of "myButton", is clicked
//You can use any jQuery/JavaScript event that you'd like to trigger the call
$('.myButton').click(function() {
//Send the AJAX call to the server
$.ajax({
//The URL to process the request
'url' : 'page.php',
//The type of request, also known as the "method" in HTML forms
//Can be 'GET' or 'POST'
'type' : 'GET',
//Any post-data/get-data parameters
//This is optional
'data' : {
'paramater1' : 'value',
'parameter2' : 'another value'
},
//The response from the server
'success' : function(data) {
//You can use any jQuery/JavaScript here!!!
if (data == "success") {
alert('request sent!');
}
}
});
});
You're hitting the Same Origin Policy with regard to ajax requests.
In a nutshell, JS/Ajax is by default only allowed to fire requests on the same domain as where the HTML page is been served from. If you intend to fire requests on other domains, it has to support JSONP and/or to set the Access-Control headers in order to get it to work. If that is not an option, then you have to create some proxy on the server side and use it instead (be careful since you can be banned for leeching too much from other sites using a robot).
As others have said you can't access files on another server. There is a hack tho. If you are using a server side language (as i assume you are) you can simply do something like:
http://myserver.com/google.php:
<?php
echo get_file_contents('http://www.google.com');
?>
http://myserver.com/myscript.js
$.get('google.php',function(data){ console.log(data) });
That should work!
you just can access pages from your domain/server

Categories

Resources