10

Suppose I use ajax (e.g. via jQuery) to do POST request to an API that implements a PRG pattern. Hence it will redirect me:

POST /some/api
HTTP/1.1 303 See Other
Location: /some/other/location

jQuery will then automatically follow the redirect and perform a:

GET /some/other/location

And then call the response handlers (success, failure, etc) with the output from the latter request. However, how can I read the location of the final resource (/some/other/location in this case) in javascript?

rlemon
  • 17,518
  • 14
  • 92
  • 123
Jeroen Ooms
  • 31,998
  • 35
  • 134
  • 207
  • According to [this answer](http://stackoverflow.com/a/8056313/759866), it is being implemented in the latest browsers. – BenMorel Jun 20 '16 at 21:49

5 Answers5

11

While this is an old post, hopefully this updated (2018) answer will help someone. Note that this solution does not work in Internet Explorer (any version), and only works in relatively modern versions of other browsers.

XMLHttpRequest now exposes a read-only property called responseURL, which returns the URL of the response after any redirects have occurred.

var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://example.com', true);
xhr.onload = function () {
  console.log(xhr.responseURL); // Prints http://example.com
};
xhr.send();

See docs at https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseURL

Fred Vollmer
  • 171
  • 3
  • 9
5

As far as I know, it's not possible with the XMLHttpRequest object. But, if you're operating within your [trusted] domain, and if it's important information, you could use an iframe instead:

var hidden_iframe = document.createElement('iframe');
hidden_iframe.name = 'hidden_iframe';
hidden_iframe.style.display = 'none';
hidden_iframe.onload = function() {
  console.log(hidden_iframe.contentWindow.location.toString());
}
document.body.appendChild(hidden_iframe);

var request = document.createElement('form');
request.method = 'post';
request.action = '/some/api';
request.target = 'hidden_iframe';
request.style.display = 'none';

// append INPUTs to the request form here

document.body.appendChild(request);
request.submit();

Your console should report 1 or more URLs, the last of which will be:

http(s)://{yourdomain}/some/other/location

svidgen
  • 13,744
  • 4
  • 33
  • 58
  • Thank you for this suggestion. Using frames instead of `XMLHttpRequest` gets a bit hairy with event handling, etc. But it could be useful in some cases. – Jeroen Ooms May 15 '13 at 18:56
4

XMLHttpRequest doesn't expose the final URL.

:[

But, you can hack around this without using an iframe. If you're returning a JSON object, you could add a finalURL property, like the following:

{ "finalURL": "http://example.com/API/v2/request.json", "response": {...} }

and read that to get the post-redirect URL. Hope that's helpful!

Community
  • 1
  • 1
Chris
  • 5,876
  • 3
  • 43
  • 69
0

I believe this is not possible in general, although I can see via Chrome Developer Tools that the browser does get a 303 response from the server and then follows the redirect.

See this related question and answer: Is it possible for XHR HEAD requests to not follow redirects (301 302)

Community
  • 1
  • 1
gb96
  • 1,674
  • 1
  • 18
  • 26
0

This is an old post but it ranks highly in Google so I'll add my solution.

If you have control over the ajax response, you could add a header to the response with the final URL.

In PHP this would be something like:

header('X-final-url: /some/other/location').

Then, in jquery, you can access this value with:

var finalUrl = jqXHR.getResponseHeader('X-final-url');

I add the header in Symfony with a kernel listener:

Service

app.kernel.response_metadata_populator:
    class: AppBundle\Listeners\ResponseMetadataPopulator
    tags:
        - { name: kernel.event_listener, event: kernel.response, method: onKernelResponse }

Listener Class

class ResponseMetadataPopulator
{
    /**
     * @param FilterResponseEvent $event
     */
    public function onKernelResponse(FilterResponseEvent $event)
    {
        $response = $event->getResponse();
        $response->headers->set('X-FINAL-URL', $event->getRequest()->getRequestUri());
    }
}
jxmallett
  • 4,087
  • 1
  • 28
  • 35