Reputation: 913
I am trying to get a File from an api url. My objective is to show this file (that was previously uploaded) in an input file field with its name. At the moment I have created the following service function:
getDocument(): Observable<Blob> {
const request = this.documentUrl;
return this.http.get(request, { responseType: 'blob' });
}
And when I use it
this.myService.getDocument().subscribe(
response => {
console.log(response);
}
I get a Blob which by definition doesn't have a name. I have seen that I can convert it into a file and give it a name but this solution doesn't fit my necessities. Is there a way I can get a File from the backend instead or is there a way to reconstruct it from the Blob with the original name it had?
Upvotes: 5
Views: 10676
Reputation: 1
Please make sure that the backend API sets the file name in the response header. Usually, the file name is included in content-disposition header.
I found it thanks to this answer and also this that CORS policy don't allow Angular to see all the headers, I'm using Java as the backend and this was how I solved the issue:
Angular:
this.myService.downloadBlob(BlobID).subscribe(
(response: HttpResponse<Blob>) => {
//same code as andsilver
// Extract content disposition header
const contentDisposition = response.headers.get('content-disposition');
// Rest of your code to extract filename using contentDisposition
// Extract the file name
const filename = contentDisposition
.split(';')[1]
.split('filename')[1]
.split('=')[1]
.trim();
this.downloadBlob(new Blob([(response.body)], { type: 'text/plain' }), filename);
}
Service Angular:
downloadBlob(BlobID: number): Observable<HttpResponse<Blob>> {
return this.http.get(myUrl+'?BlobID='+BlobID, { observe: 'response', responseType: 'blob' });
}
Server side (Java in my case):
@GetMapping("/downloadBlob")
public ResponseEntity<byte[]> downloadBlob(@RequestParam("BlobID") BigDecimal BlobID) {
BlobAndName blobAndName = service.getDocumento(BlobID);
byte[] blobAsBytes = Utils.blob2ByteArray(blobAndName.getBlob());
HttpHeaders head = new HttpHeaders();
head.add("content-disposition", "attachment; filename=" + blobAndName.getName());
ArrayList<String> exposedHead = new ArrayList<>();
exposedHead.add("content-disposition");
head.setAccessControlExposeHeaders(exposedHead);
return ResponseEntity.ok().headers(head).body(blobAsBytes);
}
I must say that due to security concerns from my colleagues (that were not explained to me, so I don't even know what they are), this is not the solution I implemented, I got the name and the blob in different methods as I had the chance to do so by recycling a previous one that already got me different information I needed and which now gives me the blob name too.
Upvotes: 0
Reputation: 5972
Please make sure that the backend API sets the file name in the response header. Usually, the file name is included in content-disposition
header.
For example: it looks like content-disposition: attachment;filename=XYZ.csv
.
In angular, You can extract it like below:
.subscribe((response: HttpResponse<Blob>) => {
// Extract content disposition header
const contentDisposition = response.headers.get('content-disposition');
// Extract the file name
const filename = contentDisposition
.split(';')[1]
.split('filename')[1]
.split('=')[1]
.trim()
.match(/"([^"]+)"/)[1];
});
Upvotes: 5