New session after download - angular js - internal rest call - angularjs

I have an ng-click implementation that does a $http.post() call to the server which returns a file content. so, a file download happens on the browser. below is the code snippet:
$scope.downloadFile = function(mediaObj) {
var downloadReq = {
"cid": $cId,
"pid":$pId,
"mid":$mId
};
$http.post(<server url>, downloadReq)
.then(function(response) {
var downloadUrl = URL.createObjectURL(new Blob([response.data]));
var a = document.createElement('a');
a.href = downloadUrl;
a.target = '_blank';
a.download = response.headers('Content-Disposition').split(';')[1].trim().split('=')[1];
document.body.appendChild(a);
a.click();
a.remove();
}, function(response) {
//unable to download
$scope.downloadErr = true;
});
}
server side code snippet is like this:
public void handleDownloadRequest(String json, HttpServletRequest request, HttpServletResponse httpServletResponse) {
....
// make rest call to another microservice to get file content
IOUtils.copyLarge(new ByteArrayInputStream((byte[])response.getBody()), httpServletResponse.getOutputStream());
// copy all headers from rest call response to httpServletResponse
httpServletResponse.flushBuffer();
}
after this, the next call to server (it need not be download itself, any other server call) is getting a brand new session. the old session has been destroyed.
because of this, server side client session state is lost and working on the client is messed up.
can anyone please help me with understanding why a new session is getting created after the download operation? how i can avoid this? why is the old session getting destroyed?
Thanks in advance.

I am answering my own question. Maybe it will save someone's time. As part of the handleDownloadRequest() method, i was making a rest call to another microservice to get the file data. the httpresponse of that rest call had a new session id that was also getting copied into the httpServletResponse of the handleDownloadRequest() method.
this was getting propagated to the client and in turn the client session state was lost.
SOLUTION: i removed the session cookie header from the response while copying over the headers.
Take care of the http response while making internal rest calls...

Related

s it possible to implement file upload function?

We are implementing file download function.
UI, service API server, and file server (external server) exist, and I cannot access the file server. (Code cannot be changed)
Currently, a file is downloaded by requesting UI -> FileServer.
I want to configure UI -> Service API -> File Server for multiple file downloads and exception handling.
As the service API operates in the middle, the final value of http that the client receives is different, but I don't know why.
Existing file servers returned an ArrayBuffer,
It was changed to a long string in String format while going through my service API server.
// my Server -> fileServer (GET Http Request)
// setting header...
// setting uri...
HttpEntity req = new HttpEntity<>(httpHeaders);
RestTemplate rt = new RestTemplate();
HttpEntity<byte[]> result = rt.exchange(
uri,
HttpMethod.GET,
req,
byte[].class
);
byte[] blob = result.getBody();
The reason why I received byte[] through result.getBody() is that I thought that the return value of the file server would be a file, and it would be a byte[] type in Java.
// react (client code)
// blobFromApi = The result my server responded
let blob = new Blob([blobFromApi], { type:'image/png' });
if (navigator.userAgent.match('CriOS')) {
let reader = new FileReader();
reader.onload = function (e) {
window.location.href = reader.result;
};
reader.readAsDataURL(blob);
} else {
FileSaver.saveAs(blob, file.file_name);
}
});
In conclusion, is it possible to implement a file download function in my current situation?

form-data works using postman but not in react, post method, Springboot

We are using react js with springboot. We have written the service and check from postman form-data. It's working but when we use react js it's not working. Rest End point hit but not load the payload data to the service.
for React we are using const formData = new FormData() and append all the required input.
React Code
const formData = new FormData();
formData.append("event", this.state.status);
formData.append("startDate", this.state.startDateTxt);
formData.append("sourceSystem", this.state.sourceSystem);
formData.append("endDate", this.state.endDateTxt);
formData.append("minPrice", this.state.minPrice);
formData.append("maxPrice", this.state.maxPrice);
httpRequest.open("POST", "http://localhost:8080/sa/searchData", true);
httpRequest.setRequestHeader("Content-Type","application/form-data");
httpRequest.onreadystatechange = () => {
console.log("httpRequest.readyState",
httpRequest.readyState);
if (httpRequest.readyState === XMLHttpRequest.DONE
&& httpRequest.status === 200) {
console.log("httpRequest.responseText ", httpRequest.responseText);
updateData(JSON.parse(httpRequest.responseText));
}
};
httpRequest.send(formData);
spring boot
#PostMapping(value = "/sa/searchData")
public List<DataResponse> searchData(SearchCriteria searchCriteria) {
return saService.searchData(searchCriteria);
}
The error code '408' suggests that the problem is in the react code that is sending form data.
The server sends '408' error when the client has sent an incomplete request to it.
The problem can be traced to the block of statements beginning from
'httpRequest.open("POST", "localhost:8080/sa/searchData", true); ...
This code block is opening the connection with the server, but never finishing sending the request.
This is causing the server to time out waiting for the complete request from client, and eventually send 408 error.
How to fix the problem?
Add a .send() method after .open() to complete the sending of the HTTP request.
An example of working code snippet:
httpRequest.open('POST', "localhost:8080/sa/searchData", true)
// add headers and other parameters
// Send the request
httpRequest.send()
More information:
https://malcoded.com/posts/react-http-requests-axios/

How to send backend errors/success messages from Node.js to frontend in AngularJS controller?

I have an application built on the MEAN stack, with ExpressJS.
There is a need to send success or error messages from backend (NodeJS) to frontend (AngularJS) for example - to show when a file was successfully uploaded. Below - after app.post is successfully completed, I would like to show this result on frontend (in AngularJS).
app.post('/upload' , function (req, res) {
//busboy handles multi-part file upload
console.log('Post received to upload ...');
var fstream;
req.pipe(req.busboy);
req.busboy.on('file', function (fieldname, file, filename) {
//only update if the filename was change or exists
if (filename!== undefined || filename !=='') {
//reset url
options.url = '';
console.log("Uploading the file " + filename);
console.log("before", options);
options.path = '/uploads/' + filename;
options.fileName = filename; //update file name
console.log("Updating options ...", options);
fstream = fs.createWriteStream(__dirname + '/uploads/' + filename); //path where the file will be uploaded
file.pipe(fstream);
fstream.on('close', function () {
console.log("Upload finished successfully ! Uploaded " + filename);
initOntology();//initialize the ontology from upload
initEdges();
});
}
});
});
Is there any way that I can send the result from NodeJS to AngularJS controller?
There is a similar question here, but unsolved.
You should use socket.io
When the frontend starts up, it connects to a 'socket connection'. This is a different protocol to HTTP. If it can't do so, it uses a degraded version of the connection which works over HTTP.
Either end of the connection can 'emit' a message, which gets sent to the other end. The backend can send messages to all clients or to specific ones. You would set up Angular to receive the message and create its own event which one or more controller could be listening for. See https://github.com/btford/angular-socket-io When the frontend wants to send a message back to the backend, it can use the socket, or just a regular HTTP POST, etc.
Using this with Angular and Node is quite standard, there should be lots of information out there on how to do it.
Just send a http response back using the res object :
res.status(200).send('OK')
When error, send, a error status
res.status(500).send(errorMsg)
For angular :
$http.post(...).then(function successCallback(response) {
// response with 200 status
}, function errorCallback(response) {
// response with status 500
});

Dart and Client Side File Handling (with authorization)

A server side application requires authorization on file download links. This means a normal <a ng-href="{{createLinkToFile()}}"> is no longer sufficient to get enough parameters passed to the server.
When trying to use a programmatic call to the file download, I get the response data back to Dart client application. Using a simple http GET:
var url = "http://example.com/file";
headers.putIfAbsent("Authorization", () => "bearer " + token;
_http.get(url: url, headers : headers);
The future returned by the GET will hold the data, but how do I instruct the browser to download it as a file, instead of just trying to keep it in memory?
Or is there a way to just do it in a normal link?
After downloading the data from the server like shown in Using Dart to Download a PNG File (Binary File) and displaying it not working you can create a download link like shown at http://blog.butlermatt.me/2014/03/dynamically-generating-download-files/
import 'dart:html';
void main() {
List body = [ 'Some test data ...\n'];
// Create a new blob from the data.
Blob blob = new Blob(body, 'text/plain', 'native');
// Create a data:url which points to that data.
String url = Url.createObjectUrlFromBlob(blob);
// Create a link to navigate to that data and download it.
AnchorElement link = new AnchorElement()
..href = url
..download = 'random_file.txt'
..text = 'Download Now!';
// Insert the link into the DOM.
var p = querySelector('#text');
p.append(link);
}
The code of Seth solves indeed part of the problem. To make it a bit more complete, I'm now using the following:
void doPdfFileRequest(String url) {
var request = new HttpRequest();
request.open('GET', url);
request.responseType = "blob";
request.withCredentials = false;
request.setRequestHeader("Accept", _httpAcceptHeader);
request.setRequestHeader("Authorization", "bearer " + token);
request.onReadyStateChange
.listen((r) => onData(request, "filename.pdf"));
request.send();
}
void onData(HttpRequest request, String filename) {
if (request.readyState == HttpRequest.DONE && request.status == 200) {
if (!isIE()) {
var contentType = request.getResponseHeader("content-type");
AnchorElement downloadLink = new AnchorElement(
href: Url.createObjectUrlFromBlob(request.response));
downloadLink.rel = contentType;
downloadLink.download = filename;
var event = new MouseEvent("click", view: window, cancelable: false);
downloadLink.dispatchEvent(event);
} else {
var href = Url.createObjectUrlFromBlob(request.response);
window.open(href, "_self");
}
}
}
A few things to notice. Instead of using the downloadLink.click(), a mouse event is constructed to ensure that it works on Firefox as well as on Safari and Chrome. Firefox seems not to handle the click() otherwise. Binding it to the DOM as is done in the code of Seth isn't necessary.
Internet Explorer doesn't understand the download attribute, so nothing will happen, therefore a window.open is used to at least have it work (though not ideal) on IE, it's redirecting to self to avoid being hit by the pop up blocker.
There are solutions that convert the result download result to Base64 first and put it in a data:mimetype href, using the blob this isn't necessary.
A nice way to set the filename on the file to download would be through the content disposition header, but this header is marked as unsafe, so cannot be used. The filename is now set in the code.
Another note, notice that a HttpRequest is used instead http.get(), The HttpRequest allows you to set the responseType, in this case blob, which can be transformed into a object url.

Silverlight Upload file to MVC3 controller endpoint (Server Respose NotFound )

I'm developing a recorder in silverlight and I need to upload data from stream to the web server after recording process is completed.
On server side I'm using ASP.NET MVC 3, and I have created a Controller with method FileUpload.
public class FileUploaderController : Controller
{
[HttpPost]
public ActionResult FileUpload(string fileName)
{
....
}
}
In silverlight applet, the upload is made by parts, about 20000 bytes at time. Servers web config is configured to accept larger amount of data.
Server returns an exception "The remote server returned an error: NotFound.".
In this case the request have not reached the action and I can't understand why.
Example of code that is used to start upload:
UriBuilder httpHandlerUrlBuilder = new UriBuilder("http://localhost:37386/FileUploader/FileUpload/?fileName=" + Guid.NewGuid() + ".wav");
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(httpHandlerUrlBuilder.Uri);
webRequest.Method = "POST";
webRequest.ContentType = "multipart/form-data"; // This solved my problem
webRequest.BeginGetRequestStream(new AsyncCallback(WriteToStreamCallback), webRequest);
EDIT
My route configuration is by default:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
When the small amount of data is sent, everything goes well and server receives the requested data. But when data to be send is larger I'm just getting NotFound response. This doesn't make any sense to me, what I'm doing is:
HttpWebRequest to send 20000 bytes
close request stream (obtained from request.EndGetRequestStream)
wait for server response (from webRequest.EndGetResponse) This is where error occurs.
In my case, I never send more than 20000 bytes, which is strange this to work sometimes and others not.
I don't know a better way to explain this problem. If you need I can provide more code and more information.
Any help is very much appreciated.
With filddler I was able to get more detailed information regarding to the error. It was "upload file potentially dangerous Request.Form value was detected from the client...".
To solve this I've specified content-type of the webRequest to "multipart/form-data"

Resources