I've generated a PDF report using JSRepoprts library. The output result is a blob that can be downloaded to the "Downloads" folder. What I need to do is to save the blob in a specific folder on the server. I tried to send the blob using XMLHttpRequest, but I'm receiving the request with empty content in the controller.
The code I wrote is the following
jsreports.export({
format: 'pdf',
report_def: def,
datasets: data_sources,
outputHandler: function (pdfBlob) {
$('.report-output-pdf').attr('src', URL.createObjectURL(pdfBlob));
var xhr = new XMLHttpRequest();
xhr.open('GET', '/reports/saveReport', true);
xhr.onload = function () {
console.log(xhr.responseText);
};
xhr.send(pdfBlob);
}
});
On the server side (MVC Controller) the code is:
public ActionResult saveReport()
{
try
{
var r = Request;
int l = Request.ContentLength; // Received 0
byte[] ba = r.BinaryRead(r.ContentLength);
return Json(r, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
return Json(new { Message = ex.Message }, JsonRequestBehavior.AllowGet);
}
}
Result as shown in debugger
Any one have an idea that help me saving the pdf blob to specific directory using the correction of the code above or any other idea?
Related
I've got a problem in my ASP.net Core application. I use MVC. I send a file from js to controller using:
var xhr = new XMLHttpRequest();
xhr.open("POST", "/Test/Sing", true);
xhr.send(fd);
then I got it in controller action:
[HttpPost]
public IActionResult Sing()
{
var file = Request.Form.Files[0];
byte[] filedata = null;
using (var target = new MemoryStream())
{
file.CopyTo(target);
filedata = target.ToArray();
}
\\some filedata processing
return RedirectToAction("Question");
}
The filedata is something that I need to process and then redirect to another action. When I put a breakpoint at the end of using (MemoryStream) I can see that the filedata is filled with data I need but when I want to redirect to action nothing happens. It looks like a process with the xmlhttprequest is still running on the client side and waiting for response. Am I right? How to get the file, cut the process, perform some file processing and be able to redirect to another action?
You should manually handle the redirect using window.location.href in success callback function of ajax/XMLHttpRequest .
If using XMLHttpRequest ,you can add listener for load events ,the listener must be added before the send() function:
function reqListener () {
window.location.href = "url";
}
var oReq = new XMLHttpRequest();
oReq.addEventListener("load", reqListener);
oReq.open("GET", "http://www.example.org/example.txt");
oReq.send();
If using AJAX redirect in success callback function :
success: function (response) {
window.location.href = "url";
}
Controller :
return Json("ok");
//Or return the url
return Json(new { redirectToUrl = Url.Action("action", "contoller") });
I am trying to download PDF file from FTP server with Jquery Ajax request. I referred http://www.dave-bond.com/blog/2010/01/JQuery-ajax-progress-HMTL5/.
My Jquery ajax call is as below
$.ajax({
xhr: function () {
var xhr = new window.XMLHttpRequest();
//Download progress
xhr.addEventListener("progress", function (evt) {
console.log("Event :"+evt.lengthComputable);
if (evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total;
//Do something with download progress
console.log(percentComplete);
}
}, false);
return xhr;
},
type: 'POST',
url: "Downloader.ashx",
success: function (data) {
//Do something success-ish
}
});
And My C# generic handler code to download file is as below
public void ProcessRequest(HttpContext context)
{
DownLoadFilesFromFTp("MyFile.pdf", "Foldername");
}
public bool DownLoadFilesFromFTp(string fileName,string ftpFolder)
{
//Create FTP Request.
try
{
string Ftp_Host = System.Configuration.ConfigurationManager.AppSettings["Ftp_Host"];
string Ftp_UserName = System.Configuration.ConfigurationManager.AppSettings["Ftp_UserName"];
string Password = System.Configuration.ConfigurationManager.AppSettings["Password"];
string downloadpath= System.Configuration.ConfigurationManager.AppSettings["downloadpath"];
//Fetch the Response and read it into a MemoryStream object.
string ftpurl = Ftp_Host + ftpFolder + "/" + fileName;
FtpWebRequest reqFTP;
reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(ftpurl));
reqFTP.Credentials = new NetworkCredential(Ftp_UserName, Password);
reqFTP.KeepAlive = false;
reqFTP.Method = WebRequestMethods.Ftp.DownloadFile;
reqFTP.UseBinary = true;
reqFTP.Proxy = null;
reqFTP.UsePassive = false;
FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
Stream responseStream = response.GetResponseStream();
FileStream writeStream = null;
//if (fileName.Substring(fileName.Length - 3, 3) == "pdf" || fileName.Substring(fileName.Length - 3, 3) == "PDF")
//{
writeStream = new FileStream(downloadpath + fileName, FileMode.Create);
//}
int Length = 2048; // 2048;
Byte[] buffer = new Byte[Length];
int bytesRead = responseStream.Read(buffer, 0, Length);
while (bytesRead > 0)
{
writeStream.Write(buffer, 0, bytesRead);
bytesRead = responseStream.Read(buffer, 0, Length);
}
responseStream.Close();
writeStream.Close();
response.Close();
return true;
}
catch (WebException wEx)
{
return false;
}
catch (Exception ex)
{
return false;
}
}
When I run a code files downloads to a folder without any issues and on Ajax call
if (evt.lengthComputable) {
}
When I console evt i got below result
Always returns false so i am unable to track a progress.
1) is there anything wrong with the code ?
2) Any alternative way to show progress bar while downloading pdf
For the bytes uploaded, it is quite easy to show progress bar. Just monitor the xhr.upload.onprogress event. The browser knows the size of the files it has to upload and the size of the uploaded data, so it can provide the progress info.
For the bytes downloaded, it is a little bit more difficult, because the only thing that the browser knows in this case is the size of the bytes it is receiving.
The reason of evt.lengthComputable is 0 is that the browser doesn't
know how many bytes will be sent in the server request.
There is a solution for this, it's sufficient to set a Content-Length header on the server like below, in order to get the total size of the bytes the browser is going to receive.
// prepare the response to the client. resp is the client Response
var resp = HttpContext.Current.Response;
// Add Content-Length of the file to headers
// if the headers is not set then the evt.loaded will be 0
resp.AddHeader("Content-Length", "lengthOfYourFile");
Your code JS side look fine.
I am not C# programmer, but i observed that C# server side, download the file ftp and save it to disk server, but never response/send the PDF binary to JS SIDE?
From JS side is 0 bytes download. and evt.lengthComputable is alway false/0.
I have local image URL and I want to get the blob from it.
The only way I found was to do HTTP request 'get' on the local URL, and read the returned blob... but this is such a strange way.
The code snippet using HTTP:
function readBody(xhr) {
var data;
if (!xhr.responseType || xhr.responseType === "text") {
data = xhr.responseText;
} else if (xhr.responseType === "document") {
data = xhr.responseXML;
} else {
data = xhr.response;
}
return data;
}
var xhr=new XMLHttpRequest();
xhr.open('GET',results[i],true);
xhr.responseType='blob';
xhr.send();
xhr.onreadystatechange=function()
{
var blob;
if(xhr.readyState==4)
{
blob=readBody(xhr);
uploadPhoto(blob,storageRef);
}
};
Your image needs to be converted to base64 and then from base64 in to binary. This is done using .toDataURL() and dataURItoBlob()
It's pretty fiddly process, I've created a tutorial you can follow which walks you through the process.
I am trying to download a zipped file that my server generates in my UI. I am at a loss as to how to get the file to download though. We have it setup so that we can download with window.open where we pass the url and it opens a blank page. We need to do a POST where it has a body now. I havent seen a way to send that along with a window.open. Does anyone have any pointers on how i can get access to the returned file?
Here is my current code...
#RequestMapping(method = RequestMethod.POST, value = "/archives/download", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Integer> getArchive(HttpServletResponse response, #RequestBody List<GeneratedReport> reportList) {
System.out.println(reportList.get(0).getFileLocation());
List<String> filesToDownload = new ArrayList<>();
reportList.stream().forEach(e -> filesToDownload.add(e.getFileLocation()));
filesToDownloadAndZip(response, filesToDownload, "zipped_file.zip");
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=zipped_file.zip");
return new ResponseEntity<Integer>(200, HttpStatus.OK);
}
private void filesToDownloadAndZip(HttpServletResponse response, List<String> filesToDownload, String archiveFileName) {
try {
ByteArrayOutputStream baos = FileIO.CreateArchive(filesToDownload);
if (baos != null && baos.size() > 0) {
// Set the content type and attachment header.
response.addHeader("Content-disposition", "attachment;filename=" + archiveFileName);
response.setContentType("application/zip");
response.setContentLength(baos.size());
baos.writeTo(response.getOutputStream());
response.flushBuffer();
} else {
LOG.debug("File was null or size 0, try again");
}
} catch(Exception ex)
{
LOG.debug(ex.getMessage());
}
}
The js i have is.....
$http.post('api/archives/download', $scope.downloadItems)
.success(function(data, status, headers, config) {
//I dont know what to do here..... :(
})
I am attempting to pass a PDF I have generated on frontend javascript using jsPDF to a Spring Framework MVC backend. Below is the front end code I have written:
var filename = "thefile";
var constructURL = '/daas-rest-services/dashboard/pdfPrintUpload/' + filename;
var url = restService.getUrl(constructURL);
var fileBytes = btoa(pdf.output());
$http.post(url, fileBytes).success(function(data) {
console.log(data);
})
.error(function(e, a) {
console.log(e);
console.log(a);
});
The pdf variable has been generated properly and can confirm is opens correctly when calling pdf.save("filename"). Below is the Java code which has been written on the Spring MVC backend for this call:
#RequestMapping(method = RequestMethod.POST, value = "/pdfPrintUpload/{documentName}")
public #ResponseBody String postPrintDocument(#PathVariable String documentName, #RequestParam byte[] fileBytes) {
String methodName = "postPrintDocument";
if(logger.isLoggable(Level.FINER)){
logger.entering(CLASS_NAME, methodName);
}
String check;
if(fileBytes != null){
check = "not null";
} else {
check = "null ";
}
//Decoding the bytestream
//Save to file location
//return file location
String returnValue = "HI " + documentName + " " + check;
if (logger.isLoggable(Level.FINER)) {
logger.exiting(CLASS_NAME, methodName);
}
return returnValue;
}
Each time I make a request, I am getting 400 Errors telling me:
Error 400: Required byte[] parameter 'fileBytes' is not present
I can confirm in the request payload that a large amount of data is being transmitted, however the backend does not seem to want to accept the parameter.
The purpose of doing this is that I want to be able to get the data from the pdf and then decode it on the backend so I can later publish the pdf to a location on the server. Is there something I am missing in my code for these requests to keep failing, and is there an easier more efficient way to achieve this functionality?
The solution was changing the #RequestParam to #RequestBody. #RequestParam is a parameter which is sent in the path.
#RequestParam vs #PathVariable
Try using ng-file-upload. The link and the examples are available on the link
ng-file-upload
for the sever side code try using this
#RequestMapping(value = "/pdfPrintUpload")
#ResponseBody
public void postPrintDocument(#RequestParam("file") MultipartFile file) {
InputStream is = file.getInputStream();
OutputStream os = new FileOutputStream(/*path to save file*/);
byte[] buffer = new byte[1024];
int length;
while ((length = is.read(buffer)) > 0)
os.write(buffer, 0, length);
is.close();
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}