Downloading problems with excel file size in React - reactjs

I am working with Spring-3.9.3, creating Excel files and trying to download them from React. The code works fine with small file sizes (50kb), more than this means no response from the React localhost web.
I don't know how to fix the problem as I have no idea if the error comes from Spring or React library.
The code comes from a tutorial that you can find here:
https://rieckpil.de/howto-up-and-download-files-with-react-and-spring-boot/
//react code from react
class App extends Component {
downloadExcel = () => {
fetch('http://localhost:8080/api/files')
.then(response => {
const filename = response.headers.get('Content-Disposition').split('filename=')[1];
response.blob().then(blob => {
let url = window.URL.createObjectURL(blob);
let a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
});
});
}
render() {
return (
<div className="App-intro">
<h3>Download an excel file</h3>
<button onClick={this.downloadExcel}>Download</button>
</div>
)
}
}
And here there is the Spring code that I am using:
//spring
#RestController
#RequestMapping(method = RequestMethod.GET, value = "/api/files")
#CrossOrigin(value = {"*"}, exposedHeaders = {"Content-Disposition"})
public class FileBoundary{
#GetMapping
public void getEntitiesXLS(HttpServletRequest request, HttpServletResponse response) throws Exception, IOException, InvalidFormatException{
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Contacts");
//create the excel file with Apache POI library
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment; filename=\"tickets.xlsx\"");
workbook.write(response.getOutputStream());
}
}
I can see the request in Spring console but there is no response in the React web. Anyone knows a solution for this? Thanks!

Well, the problem was the timeout response of the micro.

Related

react springboot file download error (file size increases)

I have small problem while developing react, spring boot application dashboard.
Here is my problem, I developed file upload dashboard it's requests from client (react) to
backend server side (springboot) by axios call multipart-form.
Seem there is no problem on
uploading file to server (because uploaded file opens well inside of server and the file
size is equal).
However, when I downloading the file the file size increases and cannot
open properly (It's shows alarm that the file damaged).
Now I don't know where to find the solution :( plz help me.
here is my react code which has axios call with file name:
function fileDownlod(props) {
api.responseType = 'blob'
api.defaults.headers.common[`Authorization`] = 'Bearer ' + localStorage.getItem('token')
api
.post('/filedown', { uuid: props }, header)
.then((response) => {
const name = response.headers['content-disposition'].split('fileName=')[1]
console.log(response.headers)
console.log(name)
const url = window.URL.createObjectURL(new Blob([response.data]))
const link = document.createElement('a')
link.href = url
link.setAttribute('download', name)
link.style.cssText = 'display:none'
document.body.appendChild(link)
link.click()
link.remove()
})
and this is my spring boot code (where I checked that the file size both equal)
#CrossOrigin(value = {"*"})
#RequestMapping(value = "/filedown", method= {RequestMethod.POST, RequestMethod.GET})
public void fileDown (#RequestBody FileEntity param, HttpServletResponse response) throws Exception {
String fileFullPath = fileLocation + param.getUuid();
try{
Path filePath = Paths.get(fileFullPath);
FileEntity fileEntity = fileRepository.findByUuid(param.getUuid());
if(fileEntity.getContentType().contains("image")){
response.setContentType("multipart/form-data");
}else{
response.setContentType("application/octet-stream");
}
response.setHeader("Content-Disposition", "attachment; fileName=" + URLEncoder.encode(fileEntity.getFileName(),"UTF-8"));
response.setHeader("Content-Transfer-Encoding", "binary");
// response.setHeader( "Access-Control-Allow-Headers","Content-Disposition");
response.setHeader( "Access-Control-Expose-Headers","Content-Disposition");
byte[] fileByte = FileUtils.readFileToByteArray(new File(fileFullPath));
System.out.println("file size of fileByte: " + fileByte.length);
System.out.println("file size of file inf. from DB: " + fileEntity.getFileSize());
response.getOutputStream().write(fileByte);
response.getOutputStream().flush();
response.getOutputStream().close();
For more information, I'm develeping in macOS and when I deploy the application file download won't work in iphone eihter :( Any suggestion? thank you.
I found my answer by myself the problem was "api.responseType = 'blob'" which didn't work as responseType.
this was my solution below
api
.post('/filedown', { uuid: props }, { responseType: 'blob' }, header)

react.js file not uploading spring server

In my project, I have Spring Boot in the back-end and React.js in the front.
My back-end is working fine, I know, because I have tested it with Postman.
In the front-end to upload file, I have a named SubmitAssignment, which looks like this:
state={file:''};
uploadFile = (e) =>{
e.preventDefault();
var formData = new FormData();
formData.append("file", this.state.file);
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://localhost:8080/uploadFile");
xhr.onload = function() {
console.log(xhr.responseText);
var response = JSON.parse(xhr.responseText);
if(xhr.status === 200) {
console.log("upload successful");
} else {
console.log("upload failed");
}
};
xhr.send(formData);
};
onInputChange = (e) =>{
this.state.file=e.target.value;
console.log(this.state.file);
};
render() {
return (
<div>
<h1>Please select file(s):</h1>
<form>
<input className="input-file" id="my-file" type="file" onChange={this.onInputChange}/>
<button onClick={this.uploadFile}>Upload</button>
</form>
</div>
);
}
But the problem is upload is failing every time. Maybe the reason is the path, not sure. I tried to console.log the path. And what I got is C:\fakepath\Screenshot (187).png
Now my question if it is because of path, how can I do it correctly(as far as I know browser doesn't allow it for security concern)?
Otherwise, what is the problem? How to solve it ?
The error in browser console :
POST http://localhost:8080/uploadFile 400
And,
{"timestamp":"2019-09-16T07:20:30.382+0000","status":400,"error":"Bad Request","message":"Required request part 'file' is not present","trace":"org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present\r\n\tat
.......
Here is the full error message.
If the REST is needed, for any reason :
#PostMapping("/uploadFile")
public UploadFileResponse uploadFile(#RequestParam("file") MultipartFile file) {
String fileName = fileStorageService.storeFile(file);
String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath()
.path("/downloadFile/")
.path(fileName)
.toUriString();
return new UploadFileResponse(fileName, fileDownloadUri,
file.getContentType(), file.getSize());
}
From what I could see, in onInputChange() you are assigning the target value this.state.file=e.target.value; (This has the file path not the actual file)
Instead change to below, Important !
this.state.file=e.target.files[0];
And some suggestions are, use Fetch Api to send post request rather than using Plain old Javascript
const formData = new FormData();
formData.append("file", this.state.file);
fetch('http://localhost:8080/uploadFile', {
method: 'POST',
body: formData
})
.then(success => console.log(success))
.catch(error => console.log(error));
In your Spring boot controller use #RequestPart("file")
#PostMapping("/uploadFile")
public UploadFileResponse uploadFile(#RequestPart("file") MultipartFile file) {
//Logic
}

Throwing error while downloading file in ASP.NET Core with status code 400

I'm working on download feature. When I run code on localhost, it runs perfectly without any error. But when I uploads same code to server then it returns Failed to load resource: the server responded with a status of 400 (Bad Request) error in console of browser. For requesting and getting response from server, I have used Axios. I'm newbie to ASP.NET Core + ReactJS technology stack and working on APIs for the first time so it's being difficult for me to figuring out root cause of this error.
Here is my code for requesting data from server.
axios({
method: 'POST',
url: '/api/ImageFetch/ImageFetchPoint',
responseType: 'blob',// important
headers: {
'Content-Type': 'application/json'
},
data: filepath
}).then(function(response) {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', fileName);
document.body.appendChild(link);
link.click();
}).catch(error => {
console.log("Status:", error.response.status);
console.log("Data:", error.response.data);
});
For getting response as file(any extension) from server, I've used following code.
[HttpPost("PanImageFunction")]
[Route("api/[controller]/[action]")]
public async Task<IActionResult> ImageFetchFunction([FromBody] ImageFetchRequest request)
{
var filePath = request.ImagePath;
var filename = System.IO.Path.GetFileName(filePath);
string path="unknownpath";
try {
if (filename == null)
return Content("filename not present");
path = Path.Combine(
Directory.GetCurrentDirectory(),
"RegistrationImages", filename);
} catch(Exception ex) {
new Logger().write(ex);
}
var memory = new MemoryStream();
using (var stream = new FileStream(path, FileMode.Open))
{
await stream.CopyToAsync(memory);
}
System.Net.Mime.ContentDisposition cd = new System.Net.Mime.ContentDisposition
{
FileName = filename,
Inline = false // false = prompt the user for downloading; true = browser to try to show the file inline
};
Response.Headers.Add("Content-Type", "multipart/form-data");
Response.Headers.Add("Content-Disposition", cd.ToString());
Response.Headers.Add("X-Content-Type-Options", "nosniff");
memory.Position = 0;
return File(memory, GetContentType(path), Path.GetFileName(path));
}
private string GetContentType(string path)
{
var types = GetMimeTypes();
var ext = Path.GetExtension(path).ToLowerInvariant();
return types[ext];
}
private Dictionary<string, string> GetMimeTypes()
{
return new Dictionary<string, string>
{
{".txt", "text/plain"},
{".pdf", "application/pdf"},
{".doc", "application/vnd.ms-word"},
{".docx", "application/vnd.ms-word"},
{".xls", "application/vnd.ms-excel"},
{".png", "image/png"},
{".jpg", "image/jpeg"},
{".jpeg", "image/jpeg"},
{".gif", "image/gif"},
{".csv", "text/csv"}
};
}
Complete code works perfectly on localhost. But when I uploads it on server then it throws 400 bad request error on console of browser as you can see in following image.
I have checked many forums and articles but most of the articles related to ASP.NET core giving solution related to Razor pages and not giving solutions related to ReactJS and Axios.
How can I fix this error?

File upload using react + asp.net core 2 application not working

I am trying to do a file upload functionality, where my front end contains react and server is asp.net core 2. I tried with various combinations but my code is not working.(Getting error at server end and most likely getting content-type error). Following is the snippets for both front end and server:
React Code is:
const formData: any = new FormData();<br />
formData.append("File",data[0]); // data[0] contains the file object<br/>
return axios.post(SAVE_ATTACHMENT_DATA, formData,
{headers: { 'Content-Type':'multipart/form-data' }}
)
.then(resp => {
//
}, err => {
//
})
};
ASP.NET Core 2 Code is:
[HttpPost]
[Route("upload")]
public async Task<IActionResult> Upload()
{
var files = Request.Form.Files; // getting error here in "Form"
FileUploadViewModel model = new FileUploadViewModel(); // model been defined in another file
var file = model.File;
if (file.Length > 0)
{
string path = Path.Combine(#"temp\", "uploadFiles");
using (var fs = new FileStream(Path.Combine(path, file.FileName), FileMode.Create))
{
await file.CopyToAsync(fs);
}
model.source = $"/uploadFiles{file.FileName}";
model.Extension = Path.GetExtension(file.FileName).Substring(1);
}
return BadRequest();
}
Can some one please help me with the same.
It should work like this:
React Code
const formData = new FormData();
formData.append("file", data[0]);
return axios.post(SAVE_ATTACHMENT_DATA, formData)
ASP.NET Core 2:
[HttpPost]
[Route("upload")]
public async Task<IActionResult> Upload(IFormFile file)
{
if (file.Length > 0)
{
string path = Path.Combine(#"temp\", "uploadFiles");
using (var fs = new FileStream(Path.Combine(path, file.FileName), FileMode.Create))
{
await file.CopyToAsync(fs);
}
model.source = $"/uploadFiles{file.FileName}";
model.Extension = Path.GetExtension(file.FileName).Substring(1);
}
return BadRequest();
}
Important: The name of the file in React has to be the same as the parameter name in the .NET Core method or else the IFormFile will be null. For example formData.append('sameName', data[0]); in React and IFormFile sameName in .NET Core.
All you're doing in your action is newing up your model, which then, obviously isn't going to have any file uploads associated with it, because it was created manually by you and not from the post data. Instead, you should take your model as a param to your action, and then use that instance rather than creating your own:
[HttpPost]
[Route("upload")]
public async Task<IActionResult> Upload(FileUploadViewModel model)

File upload with react + Vertx

I am working on a web application and i must upload a file the server which is written in Java + VertX
The endpoint is made like this:
private void uploadFromExcel(RoutingContext ctx) {
new ImportFromExcel(ctx.getBody(), ctx.vertx()).startImporting(ev->{
if(ev.failed()){
ctx.fail(ev.cause());
}else {
ctx.response().end();
}
});
}
And the frontend like this:
<input
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
type="file"
onChange={this.onUploadFile}
/>
<label htmlFor="flat-button-file">
<IconButton component="span">
<Icon className={'material icons'}>cloud_upload</Icon>
</IconButton>
</label>
[...]
onUploadFile = (e) =>{
const {reduxApi, setError, setWait, removeWait} = this.context
const { dispatchUploadFile } = this.props
const fileToUpload = e.target.files[0]
dispatchUploadFile(reduxApi, fileToUpload , (err,data)=>{
removeWait()
//e.target.value = null
if(err){
setError(err)
return
}
})
[...]
dispatchUploadFile: (reduxApi, file, cb) =>{
dispatch(reduxApi.actions.cryptoindexUploadExcel.post(null,file,cb))
}
I can upload the file via postman using the Header "Accept-Type":"multipart/form-data". It works fine!
Unfortunatelly I cannot upload the file via react, it throws an error. So I decided to try another solution
let reader = new FileReader()
reader.onload = (event) => {
let arrayBuffer = event.target.result
let array = new Uint8Array(arrayBuffer)
let binaryString = String.fromCharCode.apply(null, array)
console.log(binaryString)
setWait()
dispatchUploadFile(reduxApi, array , (err,data)=>{
removeWait()
if(err){
setError(err)
return
}
})
}
reader.readAsArrayBuffer(fileToUpload)
This piece of code reads the file but the backend part says "Zero byte long file". Do you have any solutions? Thanks!
I assume that on the server side you have the BodyHandler in your router:
router.route().handler(BodyHandler.create());
Now depending on the way you upload your file it might end up in 2 places:
If it is a multipart/form-data it will be available in the context under the fileUploads() getter:
Set<FileUpload> uploads = routingContext.fileUploads();
// Do something with uploads....
It it is a body upload, for example something like AJAX call application/json it ends up in the body() getter. So be sure that you're using the right headers as they are processed differently both by the browser and server during the upload.
SOLVED! The problem was in Frontend. I rewrote the upload method using the XMLTHTTPRequest this way:
onUploadFile = (e) =>{
if(!e.target.files || e.target.files.length==0) return
const {reduxApi, setError, setWait, removeWait} = this.context
const fileToUpload = e.target.files[0]
setWait()
const xhr = new XMLHttpRequest()
xhr.open('POST', getRootURL() + "/cryptoindex/index/excel")
xhr.onload = () => {
removeWait()
if(xhr.status!=200){
setError({...xhr, responseJSON: JSON.parse(xhr.responseText)})
}else{
this.refreshAll()
}
}
xhr.send(fileToUpload)
}
It is not the best solution but it works!

Resources