I have set up a simple front- & backend project for browsing & downloading files.
My backend server is written in java and the frontend is an angular application.
The backend has a path to a directory which it exposes to the frontend. The use can then use the frontend to navigate through the directories which are exposed by my backend.
Now I have set up a simple file download, which works fine without any problems EXCEPT when I try to download a jar-archive from the backend. When I try to download a .jar file, the downloaded file ends up being way larger than expected. For example: I want to download a 18mb .jar file and it ends up downloading a 30mb .jar file instead.
I'm pretty much at the end of my wits when it comes to this problem, as I'm still new to the Frontend & web environment, please keep that in mind. Thank you.
What makes this Problem even more confusing for me is that my response-header shows the correct Content length and the correct amount of transferred bytes, matching my expected file-size (see attached images). I also tried to apply the "application/java-archive" MediaType to both my Request and Response headers but this didn't fix the problem.
I hope i provided most of the Information needed to fix this, but just in case, here is the relevant code:
Backend: `
/** Snippet by @fateddy - https://stackoverflow.com/a/35683261
*
* @param path the path to the file as a String
* @return a resource representing the file to download
*/
@GetMapping("/browsable/download")
public ResponseEntity<Resource> getFile(@RequestParam (required = true) String path) {
String pathToFile = ROOT_PATH + File.separator + path;
Path pathTMP = Paths.get(pathToFile); // Temporary Path-Object
File file = new File(pathToFile);
HttpHeaders headers = new HttpHeaders();
MediaType mediatype = MediaType.APPLICATION_OCTET_STREAM;
if (resolveFileExtension(file).equals(".jar")){ // custom mediaType for .jar files
mediatype = MediaType.parseMediaType("application/java-archive");
}
try {
ByteArrayResource resource = new ByteArrayResource(Files.readAllBytes(pathTMP));
return ResponseEntity.ok()
.headers(headers)
.contentLength(file.length())
.contentType(mediatype)
.body(resource);
} catch (IOException e) {
System.err.println("Something went wrong");
throw new RuntimeException(e);
}
}
`
which is called by my frontend code: `
/**
* The wrapper function for Requesting a file Download
* Called by the HTMLElements of the "Files"-Part of the filebrowser
* @param fileClicked the file which is to be downloaded
*/
requestFile(fileClicked: string) {
if (this.currentURL === '') {
var url = fileClicked;
} else {
var url = this.currentURL + this.pathSeperator + fileClicked; // The full URL of the Child directory
}
this.dl_filename = fileClicked;
this.mediaType = 'application/octet-stream';
if (this.resolveFileExtension(fileClicked) == '.jar') {
this.mediaType = 'application/java-archive'; // apply custom mediaType for .jar files
}
this.http
.downloadFile(url, this.mediaType)
.subscribe(this.observerDOWNLOAD); // Call the Server and download the file -> calls download() inside the Observer
}
then in the httpService:
/**
* Calls the /download Endpoint to request a download of the given file
* @param filePath The relative path to the file which was requested for Download
* @returns An Observable containing the response of the Server (aka. the File as an Observable)
*/
downloadFile(filePath: string, mediaType: string) {
var httpOptions = {};
httpOptions = {
params: new HttpParams().set('path', filePath),
responseType: mediaType
};
const url = `${environment.serverUrl}/browsable/download`;
const result = this.http.get(url, httpOptions);
return result;
}
}
`
and finally downloaded: `
/**
* Downloads the given file inside a newly-created, hidden, a-tag-HTMLElement, which is destroyed afterwards
* Called by the Observer responsible for downloads
* @param response an Observable representing the File
*/
download(response: any) {
// Create a blob representing the File - https://stackblitz.com/edit/angular-blob-file-download?file=app%2Fapp.component.ts for more info
// "Blobs represent data that isn't necessarily in a JavaScript-native format."
const blob = new Blob([response], { type: this.mediaType });
const url = window.URL.createObjectURL(blob);
/** Workaround for FileDownload | Snippet customized from @Kol - https://stackoverflow.com/a/19328891
1 - Create a hidden <a> tag.
2 - Set its href attribute to the blob's URL.
3 - Set its download attribute to the filename.
4 - Click on the <a> tag.
*/
var a = document.createElement('a');
document.body.appendChild(a);
a.className = 'hidden';
a.href = url;
a.download = this.dl_filename;
a.click();
window.URL.revokeObjectURL(url);
a.remove();
}
`
And here is the picture of my request & response: (here the resulting jar file is ~30mb) GET-request