I'm downloading a file from an asp net API, but I can't get the filename with the extension sent from the server, in the browser I can see the header
"content-disposition: attachment; filename=AEDAF367-D922-470E -9D0F-09F84BDCA0AC.zip; filename*=UTF-8''AEDAF367-D922-470E-9D0F-09F84BDCA0AC.zip"
but in axios the "content-disposition" header does not arrive in the headers
headers:
content-length: "1270333"
content-type: "application/zip"
last-modified: "Wed, 27 Apr 2022 14:59:41 GMT"
my code ASP CORE
var fileName = Path.GetFileName("C:\file.zip");
Response.Headers.Add("content-disposition", "attachment;filename=" + fileName);
return PhysicalFile(reg.dirpc, MimeTypes.GetMimeType("C:\file.zip"), fileName);
my VueJS code
await api.get(url, { responseType: 'blob' }).then((response) => {
const blob = new Blob([response.data], { type: response.data.type });
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
console.log('response = ', response);
const contentDisposition = response.headers['content-disposition'];
console.log('contentDisposition = ', contentDisposition);
let fileName = 'unknown';
if (contentDisposition) {
const fileNameMatch = contentDisposition.match(/filename="(.+)"/);
if (fileNameMatch.length === 2)
fileName = fileNameMatch[1];
}
link.setAttribute('download', fileName);
document.body.appendChild(link);
link.click();
link.remove();
window.URL.revokeObjectURL(url);
}).catch((error) => {
console.log('ERRO POST: ', error);
if (error.response) {
console.log('error data=', error.response.data);
}
}
});
thanks!
I recently get this same problem.
to solve this from the server side you need to set this response header:
Access-Control-Expose-Headers: "*"
for more secure option:
Access-Control-Expose-Headers: ["Content-Disposition","Content-Type","My-Custom-Header"]
you can add your own header you like too,
this will allow AXIOS to read those headers,
reference: https://github.com/axios/axios/issues/1946#issuecomment-958790245
good luck!
Related
my problem is i had 400 bad request when i try to download a file using expo filesystem.downloadAsync on ios devise.
const shareDocument = async (event) => {
const data = JSON.parse(event.nativeEvent.data);
const documentName = data.documentName.replace(/[^a-z0-9.]/gi,'_');
const file = await FileSystem.downloadAsync(
config.API_DOC_URI + "/documents/pdf/download/" + data.documentId,
FileSystem.cacheDirectory + documentName,
{
headers : {
'Content-Type': 'application/vnd.api+json',
'Access-Control-Allow-Origin': '*',
'Authorization': "Bearer " + data.jwt,
'X-CSRF-TOKEN': data.csrf,
}
}
)
// sharing interface
try {
if (await Sharing.isAvailableAsync()) {
await Sharing.shareAsync(file.uri, {UTI:"com.adobe.pdf", mimeType:"application/pdf"});
}
} catch (e) {
console.log(e);
}
anyone has an idea how can i fix this issue.
random behavior: NOT ALL IOS DEVISES HAVE THIS PROBLEM.
You can use await FileSystem.writeAsStringAsync(fileUri, report.data, { encoding: FileSystem.EncodingType.Base64,});
where fileUri is destination url (device specific) and report.data is files url. I don't know in what format your pdf is, mine was buffer array, I ended up converting it to base64, so report.data was base64 string
I'm actually trying to download a zip file from a Gitlab REST endpoint that is supposed to return the the repository for a given projectID.
I used axios to call the endpoint and tried to directly upload the response data to S3, but it seems to be returning a corrupt file as the zip that it returns says it cannot be opened.
I am doing the downloading of this file in a serverless function and attempting to return an S3 URL to the client.
Headers for the response
res.headers {
date: 'Wed, 19 Jan 2022 13:44:42 GMT',
'content-type': 'application/zip',
'transfer-encoding': 'chunked',
connection: 'close',
'cache-control': 'max-age=0, private, must-revalidate',
'content-disposition': 'attachment; filename="third-project-eac3ea41c782df4bee4fe07ecc3bf356f7f74f47-eac3ea41c782df4bee4fe07ecc3bf356f7f74f47.zip"',
'content-transfer-encoding': 'binary',
etag: 'W/"12ae32cb1ec02d01eda3581b127c1fee"',
vary: 'Origin',
'x-content-type-options': 'nosniff',
'x-frame-options': 'SAMEORIGIN',
'x-request-id': '01FSS9A6W1RM77TYMFM6G7HKZ8',
'x-runtime': '0.063985',
'strict-transport-security': 'max-age=31536000',
'referrer-policy': 'strict-origin-when-cross-origin',
'ratelimit-observed': '2',
'ratelimit-remaining': '1998',
'ratelimit-reset': '1642599941',
'ratelimit-resettime': 'Wed, 19 Jan 2022 13:45:41 GMT',
'ratelimit-limit': '2000',
'gitlab-lb': 'fe-17-lb-gprd',
'gitlab-sv': 'localhost',
'cf-cache-status': 'MISS',
'expect-ct': 'max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"',
'report-to': '{"endpoints":[{"url":"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=r6XcPGaiU7JhlicrSC9iBZgXXCOMoBMXjU8kvxjZGb5UkUQBIjemmAOOX39m1ijVCnQROVhNNxc6B%2B4x%2FNf5ZG9cc8GLY%2BfMYUE29gJkHN624QKJRSX8HBrMqEQ%3D"}],"group":"cf-nel","max_age":604800}',
nel: '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}',
server: 'cloudflare',
'cf-ray': '6d007fcb7a8a8e63-PDX'
}
This it the code I'm using
const requestURL = `https://gitlab.com/api/v4/projects/${repoID}/repository/archive.zip?sha=${commitSHA}`;
let url = await Axios({
method: "GET",
url: requestURL,
headers: {
Accept: "*/*",
Authorization: "Bearer " + authToken,
},
})
.then(async (res) => {
const Key = "path/to/file";
const params = {
Bucket: BUCKET_URL,
Key,
Body: res.data,
ContentType: "application/zip",
};
await s3.upload(params).promise();
const URL = await s3.getSignedUrl("getObject", {
Bucket: BUCKET_URL,
Key,
ResponseContentDisposition:'attachment; filename = test.zip"',
});
return URL ;
})
.catch((error) => {
console.log(error);
});
return url;
But when I try and access this URL on my browser from the frontend, It returns a file test.zip which is larger and corrupt.
This is a screenshot of the data that I received on postman,
if I click save response and name the file filename.zip it shows the actual contents of the file.
Any help would be appreciated!
This worked!
const requestURL = `https://gitlab.com/api/v4/projects/${repoID}/repository/archive.zip?sha=${commitSHA}`;
let url = await Axios.get(requestURL,{
headers: {
Accept: "*/*",
Authorization: "Bearer " + authToken,
},
responseType:'arraybuffer'
})
.then(async (res) => {
const bufferData = Buffer.from(res.data)
const Key = "path/to/file";
const params = {
Bucket: BUCKET_URL,
Key,
Body: bufferData,
ContentType: "buffer",
};
await s3.upload(params).promise();
const URL = await s3.getSignedUrl("getObject", {
Bucket: BUCKET_URL,
Key,
ResponseContentDisposition:'attachment; filename = test.zip"',
});
return URL ;
})
.catch((error) => {
console.log(error);
});
return url;
I am using Angular 6 and Nodejs/Expressjs to avoid cross domain issue. So here is my code
In Angular i am calling:
this.httpClient.post('/uploadFile', formData, {params: params})
.pipe(map((res: any) => {return res}),
catchError((error: HttpErrorResponse) => {})
Nodejs/Expressjs:
app.post('/uploadFile', (req, res) => {
let formData
const form = new IncomingForm();
let readStream;
form.on('file', (field, file) => {
console.log('file.path>>>',file.path);
readStream = fs.createReadStream(file.path);
});
form.on ('fileBegin', function(name, file) {
//rename the incoming file to the file's name
let fileName = file.path.split("\\");
fileName[fileName.length-1] = file.name.split('.')[0];
fileName = fileName.join("\\");
file.path = fileName;
console.log('file.path', file.path);
console.log('file.name', file.name);
})
form.parse(req, function (err, fields, files) {
formData = new FormData();
formData.append("file", readStream);
formData.append('package_name', req.query.packagename);
formData.append('type', req.query.type);
formData.append('version', req.query.version);
formData.append('descr', req.query.descr);
console.log('req.query.packagename',req.query.packagename);
const axiosConfig = {
headers: {
'Content-Type': 'multipart/form-data'
}
};
let uploadRequest = request.post("WebAPiCallURL", requestCallback);
uploadRequest._form = formData;
uploadRequest.setHeader('Content-Type', 'multipart/form-data');
function requestCallback(err, res, body) {
return JSON.parse(body);
}
});
});
From requestCallback i am unable to send response to Angular6
Your not sending response from to the client. To send you can use res.send or any of the response function from Expressjs.
function requestCallback(err, response, body) { //Rename res to response to avoid conflict
res.send(body); // Send Response to Client
}
Note : As you used same variable res for request, Rename to some other name
I am converting a post API request written in javascript to typescript, but my new code seems to be not running as i do not see any network calls in the debugger. Please find my code snippets below.
javascript (working)
private resourcesAccessable(url, token, clientId, resources) {
var request = new XMLHttpRequest();
request.open('POST', url, false);
request.setRequestHeader("Authorization", "Bearer " + token);
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
console.log(request);
var response ;
request.onreadystatechange = function () {
if (request.readyState == 4) {
var status = request.status;
if (status >= 200 && status < 300) {
response = JSON.parse(request.responseText);
} else if (status == 403) {
console.log('Authorization request was denied by the server.');
return null;
} else {
console.log('Could not obtain authorization data from server.');
return null;
}
}
}
var params = "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket&response_mode=permissions&audience="+clientId;
if(Array.isArray(resources)){
for (var i = 0; i < resources.length; i++) {
params = params+"&permission="+resources[i]
}
}
request.send(params);
console.log(response);
return response;
}
typescript (not working)
resourcesAccessable(url, token, clientId, resources) {
private http: HttpClient,
private payload
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer ' + token
})
};
this.payload = new URLSearchParams();
this.payload.set('grant_type','urn:ietf:params:oauth:grant-type:uma-ticket');
this.payload.set('response_mode','permissions');
this.payload.set('audience', clientId);
this.payload.set('permission',resources);
return this.http.post(url, payload.toString(), httpOptions)
.pipe(
tap(
(data) => {
console.log('----->>>', data);
}
)
), error => {
console.log('error ' + JSON.stringify(error));
};
}
I have tried many things to run the above code but none of them worked for me.
Split your code into the following sections. Angular/RxJS is different from vanilla JavaScript. You create Observable http calls which the Subscriber then reads from.
Inject HttpClient into your class -- necessary for http calls to work. (Needs additional dependencies to work. Please refer https://angular.io/guide/http)
constructor(protected http: HttpClient) {}
Function Definition
resourcesAccessable(url, token, clientId, resources): Observable<any> {
const payload = new URLSearchParams()
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer ' + token
})
}
payload.set('grant_type', 'urn:ietf:params:oauth:grant-type:uma-ticket')
payload.set('response_mode', 'permissions')
payload.set('audience', clientId)
payload.set('permission', resources)
return this.http.post(url, payload.toString(), httpOptions)
}
Function Call
this.resourcesAccessable('', '', '', '')
.subscribe(
(data) => {
console.log('----->>>', data);
}
, error => {
console.log('error ' + JSON.stringify(error));
},
() => console.log('Completed'));
I'm receiving a byte array from server side and has converted it successfully to blob. However, when I'm trying to download it, it shows the file is corrupted. Below are my codes -
// In client side controller
this.contractsService.downloadPdf(id)
.then((result) => {
var blob = new Blob([result], { type: "application/pdf" });
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = "testing.pdf";
link.click();
});
And,
// In client side service
private headers = new HttpHeaders({ 'Content-Type': 'application/json' });
downloadPdf(id: number) {
return this.http.get(this.apiRoutes.download + "/" + id, { headers: this.headers })
.map((res: any) => res)
.toPromise();
}
Any sort of help will be very much appreciated.
Thank you.
Install file-saver
npm i --save file-saver#latest
Your service method
downloadPdf(id: number) {
return this.http
.get(this.apiRoutes.download + "/" + id, { responseType:'blob' })
.toPromise();
}
Now in your component
import { saveAs } from 'file-saver'
this.contractsService.downloadPdf(id)
.then(blob=> {
saveAs(blob, 'testing.pdf');
});
This should do the trick. The HttpClient will now extract the file from the stream. Also have a look in the documentation for blobs with the HttpClient.
In client side service, try explicitly setting the response type of the get request:
downloadPdf(id: number) {
return this.http.get(this.apiRoutes.download + "/" + id, { headers: this.headers; responseType: 'arraybuffer' })
.map((res: any) => res)
.toPromise();
}