Post file from one remote server to another - javascript

I'm writing a Google Chrome extension. I have URL of a binary file on a remote server. I want to post that file to other server. So related function should look like this.
function postFileToExampleCom(fileUrl) {
var file = ???; // Blob with data from file located at fileUrl
var form = new FormData();
form.append('file', file);
var request = new XMLHttpRequest();
request.open('POST', 'http://example.com/post/', true);
request.send(form);
}
FormData.append() expects second argument to be a Blob object containing file data. What is the best way to get it? File is likely to be an image that is already loaded in active tab so it's preferable to use cache and not to download this file again.
UPD: I've tried downloading file with another XMLHttpRequest setting responseType = 'blob' but strangely it returns empty response.

".. File is likely to be an image that is already loaded in active tab so it's preferable to use cache and not to download this file again."
If you saved the file locally (e.g. using localStorage or fileAPI) - then you should make sure you reading it and getting a file back and not a serialized version of the data.
I would debug the line of 'var file=???' and see what is the obj that you getting there.
It's good practice to have these 3 functions for your 'request':
onload, onerror and onprogress.
I hope it helps.

Related

Write to a local JSON file from the browser [duplicate]

This question already has answers here:
Download JSON object as a file from browser
(14 answers)
Closed 7 months ago.
I'm trying to write to my local JSON file with javascript, I'm getting it from my HTML, changing it and want to write it back. I found how to read it from here but didn't find how to write to it back to the json file.
Note: I want to this without Node.js , 'fs' won't help..
My code to get the JSON file:
<script type="text/javascript" src="data.json></script>
<script type="text/javascript" src="javascrip.js"></script>
var mydata = JSON.parse(data);
Then I changed the value of the 'name', for example.
mydata["name"] = "NewName";
And then I want to send it back to the json file, update it.
I didn't really find any code to do so.
While you can't directly write to the file system due because of security constraints, you can trigger a save dialog to request the user to save the file. I use this function which works on all recent releases of the major browsers.
function download(data, filename) {
// data is the string type, that contains the contents of the file.
// filename is the default file name, some browsers allow the user to change this during the save dialog.
// Note that we use octet/stream as the mimetype
// this is to prevent some browsers from displaying the
// contents in another browser tab instead of downloading the file
var blob = new Blob([data], {type:'octet/stream'});
//IE 10+
if (window.navigator.msSaveBlob) {
window.navigator.msSaveBlob(blob, filename);
}
else {
//Everything else
var url = window.URL.createObjectURL(blob);
var a = document.createElement('a');
document.body.appendChild(a);
a.href = url;
a.download = filename;
setTimeout(() => {
//setTimeout hack is required for older versions of Safari
a.click();
//Cleanup
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
}, 1);
}
}
It is also worth mentioning that HTML5 spec has a download attribute, but it isn't currently supported on IE.
As ArtemSky said, You can't write to the local file system. The way to accomplish what you want to do would be to use a server that can write to it's local file system or a database or whatever.
So you would want to have the data stored somewhere, either a local file on the server, in the cloud, etc. or a database of some sort. Then you would set up an API on the server that you could call remotely to get the data via an XMLHttpRequest(XHR)
Then you would create another API method you can use to send the data back and then call that with the updated/new data.
Writing to the local file system is a security concern because if anyone who can write code could overwrite your system files otherwise. Preventing the ability to write to the local file system is the only way to make the web safe.
You can't write to file system due to security constraints of the browser.
You can do that only this way - https://stackoverflow.com/a/30800715/6149665

Javascript + Multipart/Form Data

I have a service which allows to fill information about some object. One of the attributes is picture. Before now I used to upload picture through file open dialog from desktop. Now want to make it possible to load picture by URL, but I have no idea how to load it by URL and make it a form-data parameter (so that both ways were possible). I'm constructing form-data like this
var fd = new FormData();
fd.append("img", imgFile);
fd.append("data", "somedata")
Try this implementation. Uploading files and JSON data in the same request with Angular JS

Generate and download excel on fly and show loader to user while file is ready to download

I am trying to create excel using poi at server side and sending it to browser.
Using href or form submit solution is working fine but tricky part is file creation taking too much time so i want to show user some message like "Processing file" so I have implemented this using simple get request and added loader before request and removed in success call back.
Problem is - instead of downloading file, file contain coming as responseText at client side and also always executes failure call back.
Please suggest how i can get file as download in success call back instead of byte data in response text.
Also tried to set content type as attachment, force download etc but nothing work for me browser not downloading file it's showing byte data in response text
Tried to open new window with download url but as mentioned file creation take time so browser shows no content error after few minute.
note hwb is workbook object in below code
file = new File(FileName+"_"+timeStamp+".xlsx");
FileOutputStream fos = new FileOutputStream(file);
hwb.write(fos);
fos.close();
file.deleteOnExit();
String contentType = "application/vnd.openxmlformats- officedocument.spreadsheetml.sheet";
ResponseBuilder response = Response.ok((Object) file, contentType);
response.header("Content-Disposition", "attachment; filename="+ file.getName());
return response.build();

Make a JSON POST request to server, receive a binary response (an Excel file), how to download it?

I'm trying to to make a POST call to server that sent JSON data to it. The server takes the JSON data, do some processing, then send back an Excel .xlsx as the response. I want the browser to open the "Save file as" dialog for the user to save. I have been looking for a clean solution to do this. But one possible solution in this question JavaScript/jQuery to download file via POST with JSON data suggest to save the Excel file on the server then send back a URL link, then open an iframe for user to download. This is a no-go for me, as the users can create thousands Excel files on the server and the server has limited saving spaces. I want the solution to be on-the-fly. Another solution I have seen suggested to convert data into form, then using form submit. Again this is a no-go, since my data is in the range of hundreds if not thousands of Excel rows.
My jQuery POST call:
$.ajax({
type: 'POST',
url: '/server/path',
data: JSON.stringify(dataSent),
processData: false,
success: function(data, textStatus, jqXHR) {
},
error: function(result, status, err) {
},
contentType: 'application/json',
dataType: 'application/vnd.ms-excel'
});
In the backend I set this :
Response.header("Content-Type", "application/vnd.ms-excel")
Response.header("Content-Disposition", "attachment; filename=\"export.xlsx\"")
What the best way to force the browser to open "Save file as ..." dialog ?
Thanks,
I'm not sure there's a way to recieve binary data via JS and then initiate the download.
If I were tasked with this, I would change the method to a GET and generate the file (as a stream) and return it with the appropriate headers (Content-Disposition, Content-Length, Content-Type)
I figure out a way around this. Instead of making a POST call to force the browser to open the save dialog, I will make a POST call to generate the file, then temporary store the file on the server, return the filename . Then use a GET call for this file with "Content-Disposition: attachment; filename=filename1". The GET call with that header will force the browser to open the "Save this file" dialog, always.
This is actually very easy with Blob URLs.
First, download the file. I'll use fetch with async/await in TypeScript (you can always use promise chains instead of async/await and/or XHR instead of fetch):
(async () => {
let response = await fetch("/post/path", {
body: JSON.stringify(data), // must match 'Content-Type' header
headers: {
'content-type': 'application/json'
},
method: 'POST',
});
let blob = await response.blob();
let filename = "file.txt";
saveBlobAsFile(filename, blob); // This function is defined below
})();
Now that you have a blob, you can pass it to a function to download it by creating a Blob URL and a hidden link:
/**
* Downloads a blob as a file.
*
* TODO: Support iOS Safari, which doesn't support the "download" attribute.
*
* #param name The name of the downloaded file
* #param blob The blob to download
*/
export function saveBlobAsFile(name: string, blob: Blob) {
// IE10 & IE11 Support, since they don't support the "download"
// attribute on anchor tags.
if (navigator.msSaveBlob) {
navigator.msSaveBlob(blob, name);
return;
}
// Create the URL and hidden anchor tag
let $hiddenAnchorTag = $('<a style="display: none;"/>');
let url = URL.createObjectURL(blob);
// Set the attributes for the download
$hiddenAnchorTag.attr('href', url);
$hiddenAnchorTag.attr('download', name);
// Insert the link and click to download
$(document.body).append($hiddenAnchorTag);
$hiddenAnchorTag[0].click();
// Clean up after ourselves
$hiddenAnchorTag.remove();
URL.revokeObjectURL(url);
}
Other Notes
The fetch response object contains the headers, so you can parse the Content-Disposition to get the filename intended by the server. I found a couple good Regexes around the web that work pretty well for this. Mileage may vary, but I recommend making a function for this and bounding it with some nice unit tests.
This works a lot better than trying to set the current location to the location of the file, because it allows you to include more details in the POST, including API keys or something similar for security, plus it allows you to handle errors/exceptions cleanly, and know when the operation is complete (such as warning on trying to navigate away from the page that the user is still waiting on a download).
Blobs even support slicing in data, so you could extend this to download large files by fetching the individual slices (yay Content-Range!) and assembling them into a single Blob, and downloading the final blob, all while giving the user a nice loading progress indicator!
You can use Blob URLs just like any other URLs. They point to the resource, so you could pass that URL to img tags, other libraries that ask for URLs, src tags, etc.
#phamductri Serving up temporary files on the server can be very dangerous! If you need to use that pattern, you'll want to abstract the filename using a table or lookup, so the user doesn't have control over the actual filenames or paths (use UUIDs in a specified directory), and make sure users can only download the files they generated. Just a few of things you need to ensure are as follows (this is not a comprehensive list):
Users can't specify an arbitrary path to save to
They could save over your database configuration file, etc.
Users can't specify an arbitrary path to read to
They could read your database configuration file, etc.
File names can't conflict.
User A generates a file with the name "accounts_to_pay.csv". User B generates a file at the same time with the same name (either maliciously or accidentally), and now User A is paying whoever User B wants them to.

How to get file contentType using file uploader in IE9

I'm trying to do a simple task. Upload a file with valums file uploader (or fine-uploader) with MVC3 application, save it in database, and let user download it again (with an action returning FileContentResult), but to do that, I need the contentType of file uploaded.
IE9 uses the "UploadHandlerForm" methods in vlaums file uploader (I'm using version 2.1.2), where I can't get the contentType.
When I'm using IE10 for example, the plugin uploads using UploadHandlerXhr, so I can get the content type and post it to the server, with that:
_upload: function(id, params)
{
...
var file = this._files[id];
var type = (file.fileSize != null ? file.fileSize : file.size);
....
//and then, add it to be posted to server:
xhr.setRequestHeader("X-File-Type", type);
}
Is there any way I cant get the contentType of the file from an input file with javascript in older browsers (like IE9)?
It's not clear what you are trying to do here at all. Are you trying to send the content-type of the file in a separate request? If so, why? The content-type is part of each MPE request. Just examine the Content-Type header of the multipart boundary that contains the file data.
Also, don't access variables/functions that start with an underscore. Those are not part of the API and may change or be removed at any time. In the future, I hope to prevent access to these internal entirely.

Categories