I am trying to download xlsx file. I post an id and using it to get data from database. Then i can create an excel file but i couldn't download it.
My backend codes:
from flask import Flask
from flask import request, jsonify, make_response, json, send_file, redirect, url_for,send_from_directory
from bson.json_util import dumps
from flask_cors import CORS
import dbConnections.Test as db
import os
app = Flask(__name__)
cors = CORS(app, resources={r"/*": {"origins": "*"}}, support_credentials=True)
#app.route("/test-report", methods=["POST"])
def downloadTestReport():
req = request.get_json();
results = db.GetTestResult(req)
return send_file('foo.xlsx', as_attachment=True)
if __name__ =="__main__":
app.run(debug=True)
And my frontend codes:
let downloadReport = (e)=>{
if(e.field ==="downloadReport"){
const objId= {testId: e.row.objId};
axios.post('http://127.0.0.1:5000/test-report', objId)
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
}
The result on my console:
I wanna download excel file which is return.
To show what Ethan's comment is in code, Assuming your backend flask code is sending the Excel file as it should, your frontend code should look like this:
axios('/test-report', {
method: 'GET', //Pretty sure you want a GET method but otherwise POST methods can still return something too.
responseType: 'blob', // important
}).then((response) => { //Creates an <a> tag hyperlink that links the excel sheet Blob object to a url for downloading.
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', `${Date.now()}.xlsx`); //set the attribute of the <a> link tag to be downloadable when clicked and name the sheet based on the date and time right now.
document.body.appendChild(link);
link.click(); //programmatically click the link so the user doesn't have to
document.body.removeChild(link);
URL.revokeObjectURL(url); //important for optimization and preventing memory leak even though link element has already been removed. In the case of long running apps that haven't been reloaded many times.
});
This is in reference to:
//https://stackoverflow.com/questions/41938718/how-to-download-files-using-axios?noredirect=1&lq=1
How to download excel in response from api react.js
Related
Have a client-side server in react that need to request files from backend server (kotlin + spring boot) to download them.
Using the request endpoint in Swagger, Postman and Insomnia, i can success download any file with any size.
In my client-side server, have a list of this files that download can be triggered by a click in an icon. I can download files that has less than 10mb with no error, but when file has more than 10mb, it fails with Failed to fetch error.
Actually, it's a weird behavior. Let say i have a file named FILE A that has under than 10mb and FILE B with 25MB (is the max size allowed to upload). In first entried of the page, if i first request to download FILE B, it throw Failed to fetch. Now, if first request is in FILE A and after FILE B, FILE B download is successed. I'm really confused what is going on here.
Code:
const options = {
method: 'GET',
headers: { "Authorization": `Bearer ${user?.token}` },
};
fetch(`http://localhost:8080/storage/download?fileName=${filePath}`, options)
.then(function (response) {
return response.blob();
})
.then(function (myBlob) {
setSpinControl(false);
const file = new Blob(
[myBlob],
{ type: 'application/pdf' }
);
const fileURL = URL.createObjectURL(file);
if (window) {
window.open(fileURL, '_blank');
}
})
.catch((err) => {
setSpinControl(false);
console.log(err)
});
Already tried some alternatives:
Using axios (throw Network Error);
Using libraries as file-saver;
Setting timeout to 9999999;
All achieve same behavior.
I read too that createObjectURL uses memory to perform download, but max size of a file is validated to be 25MB.
Some print of Network tab:
Request Header:
Request Response:
Network List:
Any tips what i can do here?
I have a backend Django REST API that also helps serve my React frontend. I currently have an issue with my API requests url paths to my Django API in production for every page except my home page...
API URL's that work:
I'm able to visit my home page, within my home page, I have a GET request to my API which works great and loads data as expected. This is the only working GET request of my website because the API URL path is correct to my urlpatterns syntax.
API URL's that DON'T work:
The issues arise when I visit a page OTHER than the home page of my React app. My API requests to Django on other pages are using the wrong URL path according to my network panel (they are also responding with index.html), which has me believe I set up my django URLs wrong.
Please checkout my configuration below:
main urls.py:
def render_react(request):
return render(request, "index.html") #<---- index.html from React
urlpatterns = [
path('auth/', include('drf_social_oauth2.urls', namespace='drf')),
path('admin/', admin.site.urls),
path('api/', include('bucket_api.urls', namespace='bucket_api')),
path('api/user/', include('users.urls', namespace='users')),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
urlpatterns += [
re_path('',render_react) #<---- Serving React index.html
]
Here is an example of the issue:
When I visit this subpage URL:
https://mywebsite.com/try-demo/ra4r7n7mdb
A GET request should be firing off too this URL:
https://mywebsite.com/api/demo/ra4r7n7mdb
However instead of sending the request to the correct URL above, it's sending to this url:
https://mywebsite.com/try-demo/api/demo/ra4r7n7mdb
This is the same problem for other parts of my website that are requesting data from my django api. So when I visit my login page (https://mywebsite.com/login), and enter my details to request an authentication token. The request for the token should be:
https://mywebsite.com/auth/token/
but instead its requesting the data through this:
https://mywebsite.com/login/auth/token/
How to fix this?
my url patterns has a catch all request, my react is then able to 404 pages that don't exist. The only problem I have is how my React app is requesting data to my API in production. (again the API request on my homepage works fine) Why are my other requests appending the first URL path of my React router URL's?
I don't want to clog this post with code, so please let me know what other information I should present here to help solve this problem?
UPDATE
I have solved the API request issues to my server. The paths are now correct according to the network panel. However, the issue still remains where I seem to be only getting my index.html as the response for these API requests (they should be data responses, not index.html)
Here is my catch all regex for Django
re_path(".*/", render_react),
re_path(r"^$", render_react)
NEW EDIT
I am now able to get one of my API data requests to respond with JSON data (as should be expected)
Here is the URL of the API request that works:
https://mywebiste.com/api/demo/idoyem1l4k/
These still don't work:
https://mywebsite.com/api/demo/tabledata/idoyem1l4k
https://mywebsite.com/api/demo/graphdata/idoyem1l4k
How I make requests:
import axios from 'axios';
const baseURL = `https://mywebsite.com/api`;
const axiosInstance = axios.create({
baseURL: baseURL,
timeout: 9000,
headers: {
Authorization: 'Bearer ' + localStorage.getItem('access_token'),
'Content-Type': 'application/json',
accept: 'application/json',
},
});
export const getData = async (dispatch, slug, cancelToken) =>
{
try
{
console.log('fired demo request')
const response = await axiosInstance.get("demo/graphdata/" + slug, { cancelToken });
dispatch({ type: 'FETCH_SUCCESS', payload: response.data });
} catch (err)
{
if ('isCancel' in err && err.isCancel())
{
return;
}
dispatch({ type: 'FETCH_ERROR' });
}
}
How can I return the actual data requested instead of my index?
It makes sense, that it always returns the index.html. Your catch all regex prevents your API calls to be called, so it always resolves to render_react. I think you have 3 options.
You try to put the catch-all patterns to the bottom of all urlpatterns - I'm not sure how reliable this is though
You do not catch all by deleting re_path(".*/", render_react), and explicitly name every react page you want to use
You change the catch-all regex to exclude your Django apps with something like re_path("(?!api).*/", render_react),
I would choose option 2, as it gives you most control of your urls
So i have achieve to get the file URL from s3 bucket with axios and in console i can click the url and it will download the file, my question is how to achieve it without click the url from console? so when i press the download button from client it will also proceed to auto click the url as a response
this is what shown in the console img
here is my code to get the url :
exportProductPrice(priceSetID, productSalability, productCategoryStatus) {
this.$http.get("/price/product_price/export?export=1", {params:{
// embeds:'price_set_id,product.salability,product.category.status',
conditions: priceSetID + productSalability + productCategoryStatus
}}).then(response => {
console.log(response.data.file,'hit')
var fileURL = window.URL.createObjectURL(new Blob([responses.data]));
var fileLink = document.createElement('a');
fileLink.href = fileURL;
fileLink.setAttribute('download');
document.body.appendChild(fileLink);
fileLink.click();
}).catch((err) => {
return Promise.reject({ Error: 'something went wrong', err});
});
},
i have an Restful API i created using Laravel, this API like this:
http://127.0.0.1:8000/api/file/pdf/{id}
and this is my code for download:
public function pdfDownload($id){
$pdf = Cv::findOrfail($id);
return Storage::download('public/pdf/'.$pdf->pdf);
}
it is worked in postman, and also in browser, it is directly download the file,
but with react.js, it is not work, this my code in react:
pdfDownload = (id) => {
fetch(' http://127.0.0.1:8000/api/file/pdf/' + id, {
method: 'get',
headers: {
Accept: 'application/octet-stream',
'Content-Type': 'application/octet-stream'
}
}).then((res) => res.json());
};
and i call this function in button like this :
<Button color="primary" onClick={() => this.pdfDownload(data.id)}>
Download
</Button>
the id is corrected, i am ensure from this, my question is how can i download file when click this button.. Thans...
XHR calls can not trigger file download, the way browser handles it. You will have to mimic a file download using javascript code yourself, using something like below:
Reference
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'file.pdf');
document.body.appendChild(link);
link.click();
Or use File Saver package, if you don't mind an extra dependency.
FileSaver Npm
I am not able to embed a blob url as an PDF in IE 11/Edge. There is a CORS issue and IE gives an 'Access Denied'. From my research on SO, I have realized that this is due to IE's inherent security restrictions. My question is is there any other way of taking the blob URL data response from the REST service and displaying it embedded in the browser. I want to avoid using any third party libraries.
The service returns as below:
function getTest(id) {
miEService.get(id)
.then(function (response) {
var fileUrl = URL.createObjectURL(response.data);
$scope.pdfData = $sce.trustAsResourceUrl(fileUrl);
});
get: function (id) {
var config = {
headers: {
accept: 'application/pdf'
}
, responseType: 'blob'
}
return $http.get(miEnv.services.eApi + '?$filter=id eq' +
' ' + id, config);
Finally inside the html the display is as below -
<object id="pdf" data={{$ctrl.pdfData}} type="application/pdf" width="100%" height="100%" alt="pdf" class="view-pdf_document">
If the rest service returns the binary data of the pdf, you could just embedd the url in your page as an Iframe rather than the binary content itself. It should render the pdf. If not, I've had success in the past just having the pdf be a link and when you click the link it opens the request to the rest service in a new tab. If the issue is that you don't want the rest service to show up in the url on the page, then you might have to proxy the request through your own server.