26

I have one backend API which basically downloads a template whenever we call it. I have provided a href on my html page hence whenever someone click on that href, it calls backend API and that file should get downloaded.

But the file is not getting downloaded.

I am using React. If i simply hit the backend from my browser, file gets downloaded but if i call that from react, it doesn't.

Any leads?

REACT CODE :

const config = require('config'); var aws4 = require('aws4'); const Promise = require('axios'); const requestHelper = { appendHeaders(request){ request.headers = request.headers || {}; if(request.headers["Content-Type"]){ return } request.headers["Content-Type"] = "application/json"; }, externalApi(request, serverResult){ if(!request.method){ request.method='POST'; } request.path = request.url this.appendHeaders(request) console.log('request',request) return Promise(request) .then((apiResponse) => { if (apiResponse.data.errors) { var error = apiResponse.data.errors; console.log('api error response: ', error); serverResult.status(400).json({ error }) } else { console.log('api response: ', apiResponse.data); serverResult.status(200).json(apiResponse.data); } }).catch((error) => { console.log('api error response: ', error); serverResult.status(400).json({ error }); }); }, getDownloadResponse(request, serverResult){ debugger; request.path = request.url this.appendHeaders(request) console.log(request); return Promise(request) .then((apiResponse) => { if (apiResponse.data.errors) { var error = apiResponse.data.errors; console.log('api error response: ', error); serverResult.status(400).json({ error }) } else { serverResult.status(200); console.log('api response status: '+200); } }).catch((error) => { console.log('api error response: ', error); serverResult.status(400).json({ error }); }); } }; module.exports = requestHelper;

BACKEND API CODE :

@RequestMapping(value = GlobalConstants.DOWNLOAD_FILE, method = RequestMethod.GET) public void downloadTemplate(HttpServletRequest hRequest, HttpServletResponse response) throws Exception { InputStream in = null; OutputStream out = null; try { if (!StringUtils.isEmpty(sampleFile)) { File file = new File(sampleFile); in = finderService.downloadFile(sampleFile); if (in != null) { MimetypesFileTypeMap mimetypesFileTypeMap = new MimetypesFileTypeMap(); response.setContentType(mimetypesFileTypeMap.getContentType(file)); String headerKey = "Content-Disposition"; String headerValue = String.format("attachment; filename=\"%s\"", file.getName()); response.setHeader(headerKey, headerValue); out = response.getOutputStream(); byte[] buffer = new byte[4096]; int length; while ((length = in.read(buffer)) > 0) { out.write(buffer, 0, length); } } } else { response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } logger.error("Internal Server error"); //Add logs for server error here also } catch (Throwable th) { response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); logger.error(th); return; } finally { if (in != null) { in.close(); } if (out != null) { out.flush(); } } } 
8
  • 1
    Any errors in the console? Not enough details to answer you. Commented Nov 20, 2016 at 18:46
  • No Error as such. I am hitting the API but file is not getting downloaded. I think server side rendering would be required? Commented Nov 20, 2016 at 18:56
  • Then add some code maybe? Commented Nov 20, 2016 at 18:56
  • Sure. Uploading the code here. Commented Nov 20, 2016 at 18:58
  • Frontend code too, if possible (GET request..) Commented Nov 20, 2016 at 19:03

2 Answers 2

47

A GET request in JS is not the same as visiting a url in your browser. You need to directly invoke a download on the client by specifying an URL, for example like this:

download() { // fake server request, getting the file url as response setTimeout(() => { const response = { file: 'http://releases.ubuntu.com/12.04.5/ubuntu-12.04.5-alternate-amd64.iso', }; // server sent the url to the file! // now, let's download: window.open(response.file); // you could also do: // window.location.href = response.file; }, 100); } 

Here it is as a working example on JSBin.

Note that if you want to download files that the browser can display (such as JSON, images, videos), they will be displayed in a new tab. If you want those types of files downloaded directly, you will need to use some workarounds, for example using blob. There are a few examples of this on here.

Sign up to request clarification or add additional context in comments.

6 Comments

Great. It worked. Thank you so much. Need one for help (I am new to the front end). How do I handle Connection refused in React? Say if backend is down.
In your Promise you have the .catch((error)) function, in that you can handle the display of an error message to the user. You can also set a timeout for axios, if it doesn't get data after that time it will throw an error.
Why setTimeout?
It's just to show how it would work with an asynchronous request (e.g. fetch). In your code you won't need to use setTimeout.
This works great, but if the file is an image it just opens in the browser instead of downloading.. any way to get around this?
|
19

You can use React 'a' element with href and download props:

 <a href={getFile.url} download={getFile.saveAsFileName}> </a> 

3 Comments

In React local development, also need to modify the local development server (Node) in order to resp the file. Thank you so much. I had researched for a couple of hours until I found your post.
this is the Best answer

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.