Change url when sending file with Express - javascript

I want to send an HTML file as a response but when it does it keeps the current url. I have read about the location method but it does not work for me, I would like something like:
The source url is this: localhost/login
Sending this answer
res.location('/live').sendFile(path.join(__dirname, "../pages/live.html"));
I was trying to get something like this
Url in browser localhost/live
With my rendered HTML file
I am doing something wrong ?

Request via AJAX, and send html content as string, then write it to document.
Front-End code:
fetch('/your-route')
.then(response => response.text())
.then(data => {
document.write(data)
})

When using .location you are only setting the response header field of location to be equal to /live. You would have to add a status code of 302 to actually change the url. But when adding a status code of 302 you would cause a redirect and the send file will not be shown as the browser will try to GET /live. So you have to have a listener for GET /live that returns your html file.
Or you could directly use res.redirect to redirect to the in that case needed /live handler.

Related

Downloading a file from a url

I don't have much JS experience but thought this should be fairly simple - still, can't get it to work.
I need to download a file from an external server (AWS - no authentication, just plain url) when a web page loads (no clicks).
Would have been nice to just use the HTML5 'download' attribute - but doesn't work in this case.
So, have tried various JS code snippets I found.
Closest I got was:
function downloadFile(url, fileName){
fetch(url, { method: 'get', mode: 'no-cors', referrerPolicy: 'no-referrer' })
.then(res => res.blob())
.then(res => {
const aElement = document.createElement('a');
aElement.setAttribute('download', fileName);
const href = URL.createObjectURL(res);
aElement.href = href;
// aElement.setAttribute('href', href);
aElement.setAttribute('target', '_blank');
aElement.click();
URL.revokeObjectURL(href);
});
}
downloadFile('https://www.google-analytics.com/analytics.js', 'gooleAnalytics.js')
While this looks like it is working it actually downloads an empty file.
Ideas?
Cheers.
Trying to download a remote file on page load.
Resulted in empty file being downloaded.
Since you're using fetch in no CORS mode here, you won't be able to read the response of it, which is why the download is blank. Looking at the URL you provided, it doesn't send an Access-Control-Allow-Origin header so you won't be able to request it in the normal way. In order for it to work, you'll need to use a CORS proxy, use the iframe hack Albert Logic Einstein mentioned, or just have people right click save link as.

Get redirect url without follow

Is there a way to get final redirect url without following it with Fetch API ?
Example:
http://some.link/1 redirects to http://some.link/2
fetch('http://some.link/1', someParams) => get 'http://some.link/2' url
without request to it.
Yes, you can use the response.url property:
fetch('http://some.link/1').then(function(response) {
console.log(response.url); // Final URL after redirections
});
The url read-only property of the Response interface contains the URL
of the response. The value of the url property will be the final URL
obtained after any redirects.
However, this will only work if the initial and all the URLs of the redirection chain have same origin.

nodejs express res.render in ajax calls

i have a problem with res.render() in expressjs
i use ajax to request on this route:
route.get('/about',authentication,(req,res)=>{
res.render('about');
});
I did some search and found out that res.render does not work with ajax calls
so how can I change and render page without res.render().
If I remove the res.render and console.log it it will work actually any code work but not res.render (by clicking a link I send a token in header with ajax request then in my route I have an authentication middleware that get the token then redirects the user to about.ejs page)
I just want to change the page. Any idea will help guys.
thx
here is the front-end request:
$(document).ready(function(){
$('#about').click(function(){
// window.location.href='/about';
$.ajax({
method:'get',
url:'http://localhost:5000/about',
headers:{"authtoken":localStorage.getItem('authToken')}
}).done(()=>{
// window.location.href='/about';
}).catch(e=>console.log('header.ejs error'));
});
});
res.render composes a html page using templates and sends the final composed result from the server to the client. It does not issue a rendering of the page in the client window.
If the request is issued by entering the URL in the addressbar of the browser, then the browser will do the request and render the result the server sends.
If you do an ajax request you will receive that response, but you are responsible to do something with it in the .done callback. The browser does not magically know what has to be done with the data if you do an ajax request. And because you do not have anything in your .done callback nothing will happen.
So you have to do something like that:
.done(response => {
var bodyContent = response.match(/<body>(.*)<\/body>/)[1]
$('body').html(bodyContent);
})
Usually ajax is used to update a portion of page using some resposne from server without refreshing page. If you want to navigate to another route instead of ajax use form submits or href. If you stick to ajax then return a JSON from the server and do the alteration using javascript
requestHandler=(req,res)=>{
res.json({data:{}})
}
Step-1: Make a public URL, say http://your-web-site.com/redirect_destination.html
Step-2: On making ajax request from front-end, redirect user to that page using .redirect() method on response
EDIT:
The point is, I don't think it's possible to render page by making an ajax request. You can prepare a URL which renders your desired page and redirect user to that URL using .redirect() method.
Your router will not render page ,it will send only response and I didnt get just for page rendering, why you are calling ajax request on click event.If dont mind you can write logic on click and change window.location with your router. It will render particular page, for that your router should be something like this:
// about page route (http://localhost:8080/about)
router.get('/about',isAuthenticated, function(req, res) {
res.sendFile(path.join(__dirname+'/public/about.html'));
});
function isAuthenticated(req, res, next) {
// do any checks you want to in here
// CHECK THE USER STORED IN SESSION FOR A CUSTOM VARIABLE
// you can do this however you want with whatever variables you set up
if (req.user.authenticated)
return next();
// IF A USER ISN'T LOGGED IN, THEN REDIRECT THEM SOMEWHERE
res.redirect('/');
}
And change your url on click to http://localhost:8080/about

In Javascript how can I redirect an Ajax response in window location

I currently have the following working piece of code (angular but applies to any JS framework):
var url = '/endpoint/to/my/file';
$http({
method: 'GET',
url: url
})
.success(function(jdata) {
window.location = url;
})
.error(function(je){
// display errors on page
});
The above is called after a form was completed and the user has clicked on "submit" (the real situation is a bit more complex than this but it is the same idea). I do the form check asynchronously, so there's no page reload.
If the request is successful, returns a binary (a pdf file), if not succesful, the request returns a 400 BadRequest with errors formatted in JS. So what I do is, if successful, I redirect to the same url to have the PDF otherwise I get the JSON error object and do something with it.
How can I refrain from making two requests if the requests is successful?
Note1: on the backend side I would like to keep only one route that does everything, check + return PDF
Note2: the current situation is pretty neat in my opinion, since I have an asynchronous form check and if successful the file downloads directly in the browser since I have "CONTENT-DISPOSITION" -> "attachment" in the HTTP header of the successful response
Update: additional information about the architecture as requested by Emile:
In my use case I have one endpoint that checks inputs (and other external requirements). For security reasons I cannot output the PDF if all requirements are not satisfied so I have to do the check prior to delivering the file ( the file is automatically generated) anyway. So having two endpoints would just be redundant and add some unnecessary complexity.
While writing I think an alternative solution could be to pass an argument on the endpoint while doing the check, so that if successful, it stops and does not generate the PDF, and then redirect to the same endpoint without the flag which will output the PDF.
So I do the check twice but only load (and generate - which is resource intensive) the file only once and I have only one endpoint...
Here's the adapted code:
var url = '/endpoint/to/my/file';
$http({
method: 'GET',
url: url+'?check'
})
.success(function(jdata) {
window.location = url;
})
.error(function(je){
// display errors on page
});
On the backend side (I use Play framework/Scala)
def myendpoint(onlyDoCheck: Boolean = false) = Action{implicit request =>
myForm.bindFromRequest.fold(
e => BadRequest(myErrors),
v => if(onlyDoCheck) Ok(simpleOkResponse) else Ok(doComputationgeneratefileandoutputfile)
)
}
The real deal
The best you could do is split your endpoint.
One for the form and the convenience of having errors without refresh.
Then, on success, redirect to your other endpoint which only downloads the file.
If the file was on the disk and wasn't auto-generated and required to be authenticated to be downloaded, you could hide the file behind a normal endpoint, do the checks, and return the file using X-Accel-Redirect header with nginx or X-Sendfile using apache.
The hack
Disclaimer: This is more of a hack than the best solution. As mention by #Iceman, Safari, IE, Safari-iOS, Opera-mini and some such browsers don't support this particular spec.
In your server-side endpoint, if the file is available without errors, you can set the header to the content-type of the file (like 'application/pdf') so the download will starts automatically.
If there are errors, don't set the header and return a json of the errors to inform the user through javascript.
Since we don't know what's behind, here's a python (Django) example:
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename=your_filename.pdf'
response.write(repport.printReport(participantId))
return response
You can handle the response in the ajax success callback:
$.ajax({
url: 'endpoint.php',
success: function(data) {
var blob = new Blob([data]);
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = "filename.pdf";
link.click();
}
});
You could also try the jQuery fileDownload plugin mentioned in this answer.

Navigate to URL with additional header

Is there anyway we can navigate (via <a/> click) to a URL with additional header in the request ? here's my code :
i have an <a href="#" id="aUsers"/> tag, and then i handle the onClick() event via JQuery :
$('#aUsers').click(function () {
var spAuthData = sessionStorage.getItem('sp-auth-data');
window.location.href = '/users.html?sp-auth-data' = spAuthData;
});
I want to put the spAuthData value in the authorization header, so i can have a clean URL
As far as I know, there is no way to manipulate HTTP headers with a plain url.
You can use headers parameter of jQuery AJAX request if it is suitable in your situation. For example, you can update the contents of some divs with AJAX HTML response.
$.ajax({
url: '/users.html',
headers: { 'Authorization': spAuthData }
}).done(function()
{
});
Otherwise, it looks like you need to make some server-side changes.
But why don't you use cookies or something like this?
Authorization is used only by unauthorized users during authorization. In my opinion, sending this header on every request from the browser manually sounds bad. The best approach is to send this header once during authorization, create a user session and store it in cookies (as an access-token, forms ticket or whatever else).

Categories

Resources