I am attempting to add the content disposition header to a response in a controller in .net 7 api controller but the result is always null in the javascript. not sure what I am doing wrong.
c# controller.
[HttpGet("{id}")]
public async Task<IActionResult> GetFile(int id)
{
var file = await _context.Attachments.FindAsync(id);
if (file == null) return NotFound();
var fileName = file.FileName;
var mimeType = file.FileType;
byte[] fileBytes = file.BinaryData;
var result = File(fileBytes, mimeType);
Response.Headers.Add("Content-Disposition", $"attachment; filename={fileName}");
Response.Headers.Add("Content-Type", mimeType);
return result;
}
in the javascript the contentdisposition is always null.
const contentDisposition = attachmentData.headers.get("Content-Disposition");
here is the JavaScript method
const handleDownloadAttachment = async (attachmentId : number) =>{
try{
const token = commonStore.token;
const headers = new Headers();
headers.append('Authorization', `Bearer ${token}`);
headers.append('Content-Type', 'application/json');
const requestOptions = {
method: 'GET',
headers: headers,
};
debugger;
const attachmentData = await fetch(`${process.env.REACT_APP_API_URL}/upload/${attachmentId}`, requestOptions);
const contentDisposition = attachmentData.headers.get("Content-Disposition");
const fileName = contentDisposition!.split("filename=")[1].replace(/\"/g, "");
const fileType = attachmentData.headers.get("Content-Type");
const data = await attachmentData.arrayBuffer();
const file = new Blob([data], { type: fileType! });
var fileUrl = window.URL.createObjectURL(file);
var a = document.createElement("a");
a.href = fileUrl;
a.download = fileName;
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(fileUrl);
history.push(`${process.env.PUBLIC_URL}/activities/${id}/${categoryId}`)
}catch(err){
setLoading(false);
console.error(err);
}
}
Related
I am sending a zip file from my nodejs server to the browser using the following
res.set("Content-Type", "application/octet-stream");
res.set("Content-disposition", `attachment; filename="`+zip_name+`.zip"`);
res.set("Content-Length", zipBuff.length);
res.send(zipBuff);
I am then fetching it by using :
fetch("/my/url", {
method: "POST",
body: formData,
})
.then(response => {
return response.blob();
})
.then(response => {
const blob = new Blob([response], {type: 'application/zip'});
const downloadUrl = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = downloadUrl;
a.download = "blah.zip";
document.body.appendChild(a);
a.click();
});
I would like to be able to use zip_name instead of blah for the filename but I can't figure out how to access the headers (in that case Content-disposition) of the response with fetch.
Could someone please explain how it's done ?
Return blob and headers in object
fetch("/my/url", {
method: "POST",
body: formData,
})
.then(response => {
const headers = response.headers
return { blob: response.blob(), headers }
})
.then(({blob, headers}) => {
/// now you can access to **headers** and blob data
});
UPD:
To access the headers use headers.get("Header name").split('=').pop()
UPD1:
const foo = async () => {
const response = await fetch("/my/url", {
method: "POST",
body: formData,
})
if(!response.ok)
thorw new Error("Some error happend")
const blod_data = await response.blob()
const header_with_name = response.headers.get("Header name").split('=').pop()
// do something with it
}
In the first promise arrow function you have access to the HTTP response headers. If you update it to return the promise from the blob function call. Then in this nested function you can return an object that includes the header value to the outer second arrow function that processes the blob data.
Updated fetch example that includes processing the Promise returned from blob-function call.
fetch("/my/url", {
method: "POST",
body: formData,
})
.then(response => {
return response.blob().then((data) => {
return {
data: data,
filename: response.headers.get('Content-disposition'),
};
});
})
.then(({ data, filename }) => {
const blob = new Blob([data], { type: 'application/zip' });
const downloadUrl = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = downloadUrl;
a.download = filename.split('=')[1];
document.body.appendChild(a);
a.click();
});
Thank you Chapo for pointing out the issue with my previous example
Trying to download excel (.xlsx) file from my restAPI.
This is my code -
let headers = new Headers();
headers.append('Content-Type', 'application/vnd.openxmlformats');
this.http
.get(
`${pathToExcel}`,
{ headers: headers, responseType: ResponseContentType.Blob }
)
.subscribe((res: any) => {
let blob = new Blob([res._body], { type: 'application/vnd.openxmlformats' });
let myUrl = document.createElement('a');
myUrl.href = window.URL.createObjectURL(blob);
myUrl.download = 'Log.xlsx';
let event = document.createEvent('MouseEvent');
event.initEvent('click', true, true);
myUrl.dispatchEvent(event);
});
The file is downloaded but it's empty.
What am I missing?
I am using aws-sdk for upload image on the s3 bucket. Please look at my code below I already spend one day in it.
uploadImageOnS3 = () => {
var S3 = require("aws-sdk/clients/s3");
const BUCKET_NAME = "testtest";
const IAM_USER_KEY = "XXXXXXXXXXXXX";
const IAM_USER_SECRET = "XXXXX/XXXXXXXXXXXXXXXXXXXXXX";
const s3bucket = new S3({
accessKeyId: IAM_USER_KEY,
secretAccessKey: IAM_USER_SECRET,
Bucket: BUCKET_NAME
});
let contentType = "image/jpeg";
let contentDeposition = 'inline;filename="' + this.state.s3BucketObj + '"';
let file= {
uri: this.state.fileObj.uri,
type: this.state.fileObj.type,
name: this.state.fileObj.fileName
};
s3bucket.createBucket(() => {
const params = {
Bucket: BUCKET_NAME,
Key: this.state.s3BucketObj,
Body: file,
ContentDisposition: contentDeposition,
ContentType: contentType
};
s3bucket.upload(params, (err, data) => {
if (err) {
console.log("error in callback");
console.log(err);
}
// console.log('success');
console.log(data);
});
});
};
Error:
Unsupported body payload object
Please help me to short out I am also using react-native-image-picker for image upload.
You have to use array buffer in body stream to pass data object.
As per the aws documentation you can pass data stream, string, array buffer or blob data type in body parameter.
Please check below code, which will resolve your issue,
import fs from "react-native-fs";
import { decode } from "base64-arraybuffer";
uploadImageOnS3 = async() => {
var S3 = require("aws-sdk/clients/s3");
const BUCKET_NAME = "testtest";
const IAM_USER_KEY = "XXXXXXXXXXXXX";
const IAM_USER_SECRET = "XXXXX/XXXXXXXXXXXXXXXXXXXXXX";
const s3bucket = new S3({
accessKeyId: IAM_USER_KEY,
secretAccessKey: IAM_USER_SECRET,
Bucket: BUCKET_NAME,
signatureVersion: "v4"
});
let contentType = "image/jpeg";
let contentDeposition = 'inline;filename="' + this.state.s3BucketObj + '"';
const fPath = this.state.fileObj.uri;
const base64 = await fs.readFile(fPath, "base64");
//console.log(base64);
const arrayBuffer = decode(base64);
//console.log(arrayBuffer);
s3bucket.createBucket(() => {
const params = {
Bucket: BUCKET_NAME,
Key: this.state.s3BucketObj,
Body: arrayBuffer,
ContentDisposition: contentDeposition,
ContentType: contentType
};
s3bucket.upload(params, (err, data) => {
if (err) {
console.log("error in callback");
console.log(err);
}
// console.log('success');
console.log(data);
});
});
};
You can check out the React Native AWS amplify documentation for the proper process. In the documentation, it is mentioned that you can pass data stream, string, array buffer, or blob data type in body parameter.
import AWS from 'aws-sdk';
import fs from 'react-native-fs';
import {decode} from 'base64-arraybuffer';
export const uploadFileToS3 = async (file) => {
const BUCKET_NAME = 'xxxxx';
const IAM_USER_KEY = 'xxxxxxxxxxxxxxxxx';
const IAM_USER_SECRET = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
const s3bucket = new AWS.S3({
accessKeyId: IAM_USER_KEY,
secretAccessKey: IAM_USER_SECRET,
Bucket: BUCKET_NAME,
signatureVersion: 'v4',
});
const contentType = file.type;
const contentDeposition = `inline;filename="${file.name}"`;
const fPath = file.uri;
const base64 = await fs.readFile(fPath, 'base64');
const arrayBuffer = decode(base64);
return new Promise((resolve, reject) => {
s3bucket.createBucket(() => {
const params = {
Bucket: BUCKET_NAME,
Key: file.name,
Body: arrayBuffer,
ContentDisposition: contentDeposition,
ContentType: contentType,
};
s3bucket.upload(params, (error, data) => {
if (error) {
reject(getApiError(error));
} else {
console.log(JSON.stringify(data));
resolve(data);
}
});
});
});
}
I would like to add a filename to my Blob file, but I don't really know how to do it, here is my code for the moment :
onClick() {
var myHeader = new Headers();
myHeader.append('Content-Type', 'text/plain');
fetch(this.props.url, {
method: 'POST',
headers: myHeader,
body: JSON.stringify(this.state.api_arg)
}).then(response => {
const filename = getFileName(response.headers.get('Content-Disposition'))
response.blob().then(myBlob => {
const fileUrl = URL.createObjectURL(myBlob)
console.log(fileUrl)
window.open(fileUrl)
})
})
}
my filename is stocked in a variable.
The answer of Niels was incomplete, to handle filename in blob you have to do it that way:
const file = new File([myBlob], filename)
const url = URL.createObjectURL(myBlob);
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', filename);
document.body.appendChild(link);
link.click();
I have a problem when downloading files from my dropbox.
While using the type 'text/csv' I can download and view txt files.
Chaning the type to 'image/jpeg' or 'application/pdf' and download the filetype gives me blank file.
Am I on the right track here or is there another way this should be done?
main.service.ts
downloadFile(id) {
const headers = new Headers();
headers.append('Authorization', 'Bearer ' + this.accessToken);
const path = `{"path": "${id}"}`;
headers.append('Dropbox-API-Arg', path);
return this.http.post('https://content.dropboxapi.com/2/files/download',
null, { headers: headers });
}
main.component.ts
downloadFileBlob(data: any, name) {
const blob = new Blob([data], { type: 'image/jpeg' });
const url = window.URL.createObjectURL(blob);
window.open(url);
}
saveFile(id, name) {
this.dropbox.downloadFile(id).subscribe((data: any) => {
this.downloadFileBlob(data._body, name); });
}
Turns out I was going at this the wrong way.
Dropbox github has an example of using sharingGetSharedLinkFile, which works about the same as filesDownload.
Replace sharingGetSharedLinkFile with filesDownload and provide a file path instead of the URL.
Something like this:
function downloadFile() {
var ACCESS_TOKEN = (<HTMLInputElement> document.getElementById('access-
token')).value;
var SHARED_LINK = (<HTMLInputElement> document.getElementById('shared-
link')).value;
var dbx = new Dropbox.Dropbox({ accessToken: ACCESS_TOKEN });
dbx.filesDownload({path: SHARED_LINK})
.then(function(data) {
var downloadUrl = URL.createObjectURL((<any> data).fileBlob);
var downloadButton = document.createElement('a');
downloadButton.setAttribute('href', downloadUrl);
downloadButton.setAttribute('download', data.name);
downloadButton.setAttribute('class', 'button');
downloadButton.innerText = 'Download: ' + data.name;
document.getElementById('results').appendChild(downloadButton);
});
}