views:

410

answers:

3

Hello

please consider this: On page A I have a link that takes you to page B when JS is off, but when JS is on, I want to replace content on current page with content from the page B.

Pages A and B are in fact the same script that is able to tell AJAX calls from regular ones and serve the content appropriately. Everything works fine, as long as there are no redirects involved.

But, sometimes there is a 301 redirect and what seems to be happening is that client browser then makes a second request, which will return with a 200 OK. Only the second request is sent without a X-Requested-With header, therefore I cannot tell within my script wether it came from AJAX or not, and will send a complete page instead of just the content.

I have tried checking for 301 status code in my error, success, and complete handlers but none of them worked. It seems to be handling the 301 behind the scenes.

Could anyone help me with this?

jQuery 1.4, PHP 5

Edit: People requested the code to this, which I didn't think was necessary but here goes:

// hook up menu ajax loading
$('#menu a').live("click", function(){
    // update menu highlight
    if($(this).parents('#menu').size() > 0){
        $("#menu>li").removeClass("current_page_item");
        $(this).parent().addClass("current_page_item");
    }
    // get the URL where we will be retrieving content from 
    var url = $(this).attr('href');

    window.location.hash = hash = url;

    $.ajax({
        type: "GET",
        url: url,
        success: function(data){
            // search for an ID that is only present if page is requested directly 
            if($(data).find('#maincontent').size() > 0){
                data = $(data).find('#maincontent .content-slide *').get();
            }
            // the rest is just animating the content into view
            $("#scroller").html(data);
            $('.content-slide').each(setHeight);

            $('.content-slide').animate({
                    left: "0px"
                }, 1000, 'easeOutQuart', 
                function(){
                    $('#home').css("left", "-760px").html(data);
                    $('#scroller').css("left", "-760px");
                    $('.content-slide').each(setHeight);
                }
            );
        }
    });

    return false;
});
A: 

Due to the fact that the headers aren't being passed properly after the redirect, it seems like a good option would be to allow for a query string variable to indicate the isAjax status of a request as well as the x-requested-with header. So if your 301 redirects are being generated by an .htaccess file, you'd just need to pass the query string arguments onto the new path when redirecting. For instance:

RewriteEngine on
RewriteRule pageB.php$ pageC.php?%{QUERY_STRING} [L,R=301]

So your request for pageB.php?isAjax=1 will be pageC.php?isAjax=1, resulting in the properly formatted response from the server.

BBonifield
see, this is a problem. The whole thing is supposed to be a Wordpress theme, so I can not really edit .htaccess. I need a way of doing this in JS or in PHP...
meosoft
Well depending on why the 301 is being generated, I'd imagine Wordpress could pass on the query string argument just the same as the .htaccess snip-it there. The only extra caveat to that is that you'd need to configure Wordpress to interpret the isAjax query string variable as a valid identifier of an AJAX request, and I'm sure that's possible.
BBonifield
A: 

Since you load pageB with either direct access and using AJAX, I usually put the simple if in page like that. Page B will looks like this:

<?php $is_ajax = ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'); ?>
<?php if ( ! $is_ajax ): ?>
<html>
<!-- full page content for direct access -->
<?php endif; ?>
<!-- page content that for AJAX request and direct access -->
<div id="maincontent">
<!-- content here -->
</div>
<!-- end of page content that for AJAX request and direct access -->
<?php if ( ! $is_ajax ): ?>
<!-- rest of page content -->
</html>
<?php endif; ?>

Then your jQuery code will not need to do checking, just get the page and add it to scroller.

//I prefer just user $.get
$.get(url, {}, 
  function(data){
    // the rest is just animating the content into view
    $("#scroller").html(data);
    //...
  });

With this, I don't need to filter the response data from AJAX request.

I have one question for you. What this code do?

window.location.hash = hash = url;

Maybe that what cause the weird redirect.

If you still experience the weird redirect, debugging using Firebug and see the apache log might help you find the bug source.

Donny Kurnia
thank you for your answer, but I already do that, it is precisely the problem, a request to / on the server causes redirect, browser in turn reloads the page at correct URL, but fails to send the http_x_requested_with, that's why the solution you suggest and I use does not work.the window.location.hash = url serves as a base for history and the ability to email current URL
meosoft
Is all AJAX request in your server doesn't have `HTTP_X_REQUESTED_WITH` or just the code in page A and page B? Maybe for workaround, you can pass a parameter when request page B: `$.get('pageB', {'partial':1}, function(data) { //process });`, but this will only for temporary fix. Don't relay on it.
Donny Kurnia
A: 

I'm having the same issue here. Jquery 1.4 that doesn't send the XMLHttpRequest HTTP header for the second request when a Location header is sent back for the first request.

This is using the $('#id').load(url); function; nothing fancy.

If somebody has a solution that doesn't involve many workarounds, it would be greatly appreciated...

Thank you all!

Johan Douma