Get redirect url without follow - javascript

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.

Related

Change url when sending file with Express

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.

Unable to decode the fetch API request, which contains % in it

I am sending a request through fetch API in react application.
The fetch url contains the name argument, I should be able to create an account for the username which contains % in it. But when i tried to pass this url, i am getting the error message as unable to decode.
Note : This is http request
Format URL : http://localhost/users/api/service/username=test12%,cn=Administrators,cn=test administration,o=nmc
The space between test and administrator converts to %20 as expected.
But the % is not allowing me to pass this request.
let constructed_URL = 'http://localhost/users/api/service/username=test12%,cn=Administrators,cn=test administration';
fetch(constructed_URL, {
method: "get",
headers: urlParameter
})
I expect the browser to decode %, and pass this request.
fetch or console.error or Chrome somewhere automagically applies decodeURI (or -Component) if it thinks it was doubly encoded.
It doesn't behave that way if the URL is encoded thrice.
I wanted to use URIencoded file names in my file system directly. It simply is impossible to fetch these files at the moment.

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.

Insert custom variable in $http post request header or body

In my project, I already have AngularJS service that inserts desired object using $http.post as follows:
function insertObject(object, callback) {
$http.post(apiUrl, object).success(function (data) {
"object" is set in corresponding AngularJS controller and sent to my service like:
objectServices.insertObject(object, function (data) {
According to this, "object" is sent through $http post request body. What I need, is to send one additional variable inside this $http request. Actually, this variable should be URL (route), with which the controller works.
I can't change this object structure (to attach new property to it, which would hold URL info etc.) because $http.post(apiUrl, object) matches corresponding backend API Controller method that takes exactly this object as parameter (this object is entity).
I tried something like this:
Declare variable that will hold URL info:
var url = window.location;
And attach it to $http.post header like:
$http.defaults.headers.common["currentUrl"]= url;
where "currentUrl" is supposed to be key and url is value.
Also tried something like:
$http.post(apiUrl, object, headers: { 'currentUrl': url })
and on backend side, inside corresponding API Controller HttpResponseMessage method tried to extract it from request header as:
Request.Headers.Single(x => x.Key == "currentUrl").ToString();
but it didn't work. Please, can someone explain how to send custom data inside http post request and tell me what wrong is with my try?
EDIT: Content of Request.Header on backend side is:
While attaching the variable:
$http.defaults.headers.post.currentUrl = url;
When making the call, you missed the braces:
$http.post(apiUrl, object, {headers: { 'currentUrl': url }})

Capture redirect location of javascript XMLHttpRequest

I know that you can't, when using an XMLHttpRequest, intercept a redirect or prevent it, as the browser will transparently follow it, but is it possible to either
A. Determine whether a request redirected, or
B. Determine where it redirected to? (assuming that the response gives no hints)
Example code:
$.post("/my-url-that-redirects/", {},
function(response, statusCode, xmlHttpRequest){
//Somehow grab the location it redirected to
}
);
In my case, firebug will first show a POST to the url, then a GET to the redirected url. Can that GET location be captured?
1) Use different status code than 301 (2**) (if request by ajax) and handle redirection on client side:
var STATUS = {
REDIRECT: 280
};
$.post('/redirected', {}, function(response, status, request) {
if (status == STATUS.REDIRECT) {
// you need to return the redirect url
location.href = response.redirectUrl;
} else {
$('#content').html(request.responseText);
}
});
2) DO NOT REDIRECT:
I use that in "redirect pattern" = redirecting after post request (you don't want to allow user to refresh the post request, etc..)
With ajax request, this is not necessary, so when the post request is ajax, I do forward instead (just forward to different controller - depends on your server-side framework, or what you are using...). POST requests are not cached by browsers.
Actually, I don't know what's the reason you need that, so this might not be so useful for you. This is helpful when server returns different responses for ajax requests than common requests, because when browser redirect ajax request, the redirected request is not XMLHttpRequest...
[updated]
You can access headers (of redirected request) like that:
$.post('redirected', {}, function(r, s, req) {
req.getAllResponseHeaders();
req.getResponseHeader('Location');
});
There should be 'Location' header, but it depends on the server, which headers are sent back...
After 4 years now it's possible to find the last redirect location using responseURL from XHR instance in Chrome 42+ (Opera 29+) and Firefox 39+ but it's not available in IE, Edge or safari yet.

Categories

Resources