javascript - एक jQuery अजाक्स कॉल के बाद एक पुनर्निर्देशन अनुरोध का प्रबंधन कैसे करें




ajax redirect (20)

मैं अजाक्स का उपयोग करके सर्वलेट को कॉल करने के लिए $.post() का उपयोग कर रहा हूं और फिर उपयोगकर्ता के वर्तमान पृष्ठ में एक div तत्व को प्रतिस्थापित करने के लिए परिणामी HTML खंड का उपयोग कर रहा हूं। हालांकि, यदि सत्र का समय समाप्त हो जाता है, तो सर्वर लॉगिन पृष्ठ पर उपयोगकर्ता को भेजने के लिए एक रीडायरेक्ट निर्देश भेजता है। इस मामले में, jQuery लॉग इन पेज की सामग्री के साथ div तत्व को प्रतिस्थापित कर रहा है, जिससे उपयोगकर्ता की आंखों को वास्तव में एक दुर्लभ दृश्य देखने के लिए मजबूर किया जा रहा है।

मैं jQuery 1.2.6 के साथ अजाक्स कॉल से रीडायरेक्ट निर्देश कैसे प्रबंधित कर सकता हूं?


अंत में, मैं एक कस्टम HTTP Header जोड़कर समस्या हल करता हूं। Just before response for every request in server side, i add the current requested url to response's header.

My application type on server is Asp.Net MVC , and it has a good place to do it. in Global.asax i implemented the Application_EndRequest event so:

    public class MvcApplication : System.Web.HttpApplication
    {

    //  ...
    //  ...

        protected void Application_EndRequest(object sender, EventArgs e)
        {
            var app = (HttpApplication)sender;
            app.Context.Response.Headers.Add("CurrentUrl",app.Context. Request.CurrentExecutionFilePath);
        }

    }

It works perfect for me! Now in every response of the JQuery $.post i have the requested url and also other response headers which comes as result of POST method by status 302 , 303 ,... .

and other important thing is that there is no need to modify code on server side nor client side.

and the next is the ability to get access to the other information of post action such errors, messages, and ..., In this way.

I posted this, maybe help someone :)


अंततः लागू किया गया समाधान अजाक्स कॉल के कॉलबैक फ़ंक्शन के लिए एक रैपर का उपयोग करना था और इस रैपर में लौटाए गए HTML खंड पर किसी विशिष्ट तत्व के अस्तित्व की जांच करना था। यदि तत्व पाया गया तो रैपर ने एक पुनर्निर्देशन निष्पादित किया। यदि नहीं, तो रैपर ने कॉल को वास्तविक कॉलबैक फ़ंक्शन पर अग्रेषित कर दिया।

उदाहरण के लिए, हमारे रैपर फ़ंक्शन कुछ ऐसा था:

function cbWrapper(data, funct){
    if($("#myForm", data).length > 0)
        top.location.href="login.htm";//redirection
    else
        funct(data);
}

फिर, अजाक्स कॉल करते समय हमने कुछ ऐसा उपयोग किया:

$.post("myAjaxHandler", 
       {
        param1: foo,
        param2: bar
       },
       function(data){
           cbWrapper(data, myActualCB);
       }, 
       "html"
);

यह हमारे लिए काम करता है क्योंकि सभी अजाक्स कॉल हमेशा एक डीवी तत्व के अंदर HTML लौटाते हैं जिसे हम पृष्ठ के एक टुकड़े को प्रतिस्थापित करने के लिए उपयोग करते हैं। साथ ही, हमें केवल लॉगिन पृष्ठ पर रीडायरेक्ट करने की आवश्यकता है।


कुछ नीचे उपयोगी हो सकता है:

मैं चाहता था कि ग्राहकों को किसी भी शेष-क्रिया के लिए लॉगिन पेज पर रीडायरेक्ट किया जाए जो प्राधिकरण टोकन के बिना भेजा जाता है। चूंकि मेरे सभी बाकी-क्रियाएं अजाक्स आधारित हैं, इसलिए मुझे अजाक्स सफलता समारोह को संभालने के बजाय लॉगिन पेज पर रीडायरेक्ट करने के लिए एक अच्छा सामान्य तरीका चाहिए।

मैंने यही किया है:

किसी भी अजाक्स अनुरोध पर मेरा सर्वर एक जेसन 200 प्रतिक्रिया "प्रमाणीकरण की आवश्यकता" लौटाएगा (यदि ग्राहक को प्रमाणित करने की आवश्यकता है)।

जावा (सर्वर पक्ष) में सरल उदाहरण:

@Secured
@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {

    private final Logger m_logger = LoggerFactory.getLogger(AuthenticationFilter.class);

    public static final String COOKIE_NAME = "token_cookie"; 

    @Override
    public void filter(ContainerRequestContext context) throws IOException {        
        // Check if it has a cookie.
        try {
            Map<String, Cookie> cookies = context.getCookies();

            if (!cookies.containsKey(COOKIE_NAME)) {
                m_logger.debug("No cookie set - redirect to login page");
                throw new AuthenticationException();
            }
        }
        catch (AuthenticationException e) {
            context.abortWith(Response.ok("\"NEED TO AUTHENTICATE\"").type("json/application").build());
        }
    }
}

मेरे जावास्क्रिप्ट में मैंने निम्नलिखित कोड जोड़ा है:

$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
    var originalSuccess = options.success;

    options.success = function(data) {
        if (data == "NEED TO AUTHENTICATE") {
            window.location.replace("/login.html");
        }
        else {
            originalSuccess(data);
        }
    };      
});

और यह इसके बारे में है।


कोई ब्राउज़र 301 और 302 प्रतिक्रियाओं को सही तरीके से संभालता नहीं है। और वास्तव में मानक भी कहता है कि उन्हें उन्हें "पारदर्शी रूप से" संभालना चाहिए जो अजाक्स लाइब्रेरी विक्रेताओं के लिए एक प्रमुख सिरदर्द है। Ra-Ajax हमें सर्वर से पारदर्शी रूप से रीडायरेक्ट को संभालने के लिए HTTP प्रतिक्रिया स्थिति कोड 278 (केवल कुछ "अप्रयुक्त" सफलता कोड) का उपयोग करने के लिए मजबूर किया गया था ...

यह वास्तव में मुझे परेशान करता है, और अगर किसी के पास डब्ल्यू 3 सी में कुछ "खींचें" है तो मैं सराहना करता हूं कि आप डब्ल्यू 3 सी को यह बता सकते हैं कि हमें वास्तव में 301 और 302 कोडों को संभालने की ज़रूरत है ...! ;)


दिए गए समाधानों में से अधिकांश एक अतिरिक्त शीर्षलेख या एक अपरिवर्तनीय HTTP कोड का उपयोग करके वर्कअराउंड का उपयोग करते हैं। वे समाधान शायद सबसे अधिक काम करेंगे लेकिन थोड़ा 'हैकी' महसूस करेंगे। मैं एक और समाधान के साथ आया हूँ।

हम WIF का उपयोग कर रहे हैं जो 401 प्रतिक्रिया पर रीडायरेक्ट (passiveRedirectEnabled = "true") को कॉन्फ़िगर करने के लिए कॉन्फ़िगर किया गया है। सामान्य अनुरोधों को संभालने पर रीडायरेक्ट उपयोगी होता है लेकिन AJAX अनुरोधों के लिए काम नहीं करेगा (क्योंकि ब्राउज़र 302 / रीडायरेक्ट निष्पादित नहीं करेंगे)।

अपने global.asax में निम्न कोड का उपयोग करके आप AJAX अनुरोधों के लिए रीडायरेक्ट को अक्षम कर सकते हैं:

    void WSFederationAuthenticationModule_AuthorizationFailed(object sender, AuthorizationFailedEventArgs e)
    {
        string requestedWithHeader = HttpContext.Current.Request.Headers["X-Requested-With"];

        if (!string.IsNullOrEmpty(requestedWithHeader) && requestedWithHeader.Equals("XMLHttpRequest", StringComparison.OrdinalIgnoreCase))
        {
            e.RedirectToIdentityProvider = false;
        }
    }

यह आपको AJAX अनुरोधों के लिए 401 प्रतिक्रियाएं वापस करने की अनुमति देता है, जो आपके जावास्क्रिप्ट को पृष्ठ को फिर से लोड करके संभाल सकता है। पृष्ठ को फिर से लोड करने से एक 401 फेंक दिया जाएगा जिसे WIF द्वारा नियंत्रित किया जाएगा (और WIF उपयोगकर्ता को लॉगिन पृष्ठ पर रीडायरेक्ट करेगा)।

401 त्रुटियों को संभालने के लिए जावास्क्रिप्ट का एक उदाहरण:

$(document).ajaxError(function (event, jqxhr, settings, exception) {

    if (jqxhr.status == 401) { //Forbidden, go to login
        //Use a reload, WIF will redirect to Login
        location.reload(true);
    }
});

निम्न-स्तरीय $.ajax() कॉल का उपयोग करें:

$.ajax({
  url: "/yourservlet",
  data: { },
  complete: function(xmlHttp) {
    // xmlHttp is a XMLHttpRquest object
    alert(xmlHttp.status);
  }
});

रीडायरेक्ट के लिए इसे आज़माएं:

if (xmlHttp.code != 200) {
  top.location.href = '/some/other/page';
}

मुझे नींबू की थोड़ी मोड़ के साथ टिममेर की विधि पसंद है। यदि आप कभी भी सामग्री लौटाते हैं तो जब आप जेएसओएन की अपेक्षा कर रहे हों तो टेक्स्ट / एचटीएमएल टाइप करें , आपको सबसे अधिक रीडायरेक्ट किया जा रहा है। मेरे मामले में, मैं बस पृष्ठ को फिर से लोड करता हूं, और यह लॉगिन पेज पर रीडायरेक्ट हो जाता है। ओह, और जांचें कि jqXHR स्थिति 200 है, जो मूर्खतापूर्ण प्रतीत होती है, क्योंकि आप त्रुटि फ़ंक्शन में हैं, है ना? अन्यथा, वैध त्रुटि के मामले एक पुनरावर्तक रीलोड (ओओएस) को मजबूर करेंगे

$.ajax(
   error:  function (jqXHR, timeout, message) {
    var contentType = jqXHR.getResponseHeader("Content-Type");
    if (jqXHR.status === 200 && contentType.toLowerCase().indexOf("text/html") >= 0) {
        // assume that our login has expired - reload our current page
        window.location.reload();
    }

});

मुझे पता है कि यह विषय पुराना है, लेकिन मैं अभी तक एक और दृष्टिकोण दूंगा जो मैंने पाया है और पहले here वर्णित here । असल में मैं डब्ल्यूआईएफ के साथ एएसपी.एमवीसी का उपयोग कर रहा हूं (लेकिन यह इस विषय के संदर्भ के लिए वास्तव में महत्वपूर्ण नहीं है - उत्तर पर्याप्त है चाहे कोई फ्रेमवर्क का उपयोग न हो। सुराग अपरिवर्तित रहता है - अजाक्स अनुरोध करते समय प्रमाणीकरण विफलताओं से संबंधित मुद्दों से निपटना )

नीचे दिखाया गया दृष्टिकोण बॉक्स के बाहर सभी AJAX अनुरोधों पर लागू किया जा सकता है (यदि वे स्पष्ट रूप से ईवेंट को पहले से परिभाषित नहीं करते हैं)।

$.ajaxSetup({
    beforeSend: checkPulse,
    error: function (XMLHttpRequest, textStatus, errorThrown) {
        document.open();
        document.write(XMLHttpRequest.responseText);
        document.close();
    }
});

किसी भी AJAX अनुरोध को करने से पहले CheckPulse विधि लागू की जाती है (नियंत्रक विधि जो कुछ भी सरल हो सकती है):

[Authorize]
public virtual void CheckPulse() {}

यदि उपयोगकर्ता प्रमाणीकृत नहीं है (टोकन समाप्त हो गया है) ऐसी विधि तक पहुंचा नहीं जा सकता है ( Authorize विशेषता द्वारा संरक्षित)। चूंकि फ्रेमवर्क प्रमाणीकरण को संभालता है, जबकि टोकन समाप्त हो जाता है, यह प्रतिक्रिया के लिए http स्थिति 302 रखता है। यदि आप नहीं चाहते हैं कि आपका ब्राउज़र पारदर्शी रूप से 302 प्रतिक्रिया को संभालने के लिए, ग्लोबल.एक्सएक्स में इसे पकड़ें और प्रतिक्रिया स्थिति बदलें - उदाहरण के लिए 200 ठीक है। इसके अतिरिक्त, हेडर जोड़ें, जो आपको विशेष रूप से इस तरह की प्रतिक्रिया को संसाधित करने के लिए निर्देश देता है (बाद में क्लाइंट साइड पर):

protected void Application_EndRequest()
{
    if (Context.Response.StatusCode == 302
        && (new HttpContextWrapper(Context)).Request.IsAjaxRequest())
    {                
        Context.Response.StatusCode = 200;
        Context.Response.AddHeader("REQUIRES_AUTH", "1");
    }
}

अंत में ग्राहक पक्ष में ऐसे कस्टम हेडर की जांच करें। यदि मौजूद है - लॉगऑन पेज पर पूर्ण पुनर्निर्देशन किया जाना चाहिए (मेरे मामले में window.location स्थान को अनुरोध से यूआरएल द्वारा प्रतिस्थापित किया जाता है जिसे मेरे ढांचे द्वारा स्वचालित रूप से संभाला जाता है)।

function checkPulse(XMLHttpRequest) {
    var location = window.location.href;
    $.ajax({
        url: "/Controller/CheckPulse",
        type: 'GET',
        async: false,
        beforeSend: null,
        success:
            function (result, textStatus, xhr) {
                if (xhr.getResponseHeader('REQUIRES_AUTH') === '1') {
                    XMLHttpRequest.abort(); // terminate further ajax execution
                    window.location = location;
                }
            }
    });
}

मुझे हेडर समाधान के साथ कोई सफलता नहीं मिली - उन्हें कभी भी मेरे AJAXSccess / AJAX पूर्ण विधि में नहीं उठाया गया था। मैंने कस्टम प्रतिक्रिया के साथ स्टीग का जवाब इस्तेमाल किया, लेकिन मैंने जेएस पक्ष को कुछ संशोधित किया। मैं एक विधि निर्धारित करता हूं जिसे मैं प्रत्येक फ़ंक्शन में कॉल करता हूं ताकि मैं मानक $.get और $.post । पोस्ट विधियों का उपयोग कर $.get

function handleAjaxResponse(data, callback) {
    //Try to convert and parse object
    try {
        if (jQuery.type(data) === "string") {
            data = jQuery.parseJSON(data);
        }
        if (data.error) {
            if (data.error == 'login') {
                window.location.reload();
                return;
            }
            else if (data.error.length > 0) {
                alert(data.error);
                return;
            }
        }
    }
    catch(ex) { }

    if (callback) {
        callback(data);
    }
}

उपयोग में इसका उदाहरण ...

function submitAjaxForm(form, url, action) {
    //Lock form
    form.find('.ajax-submit').hide();
    form.find('.loader').show();

    $.post(url, form.serialize(), function (d) {
        //Unlock form
        form.find('.ajax-submit').show();
        form.find('.loader').hide();

        handleAjaxResponse(d, function (data) {
            // ... more code for if auth passes ...
        });
    });
    return false;
}

मेरे पास एक साधारण समाधान है जो मेरे लिए काम करता है, कोई सर्वर कोड परिवर्तन आवश्यक नहीं है ... बस एक टीएसपी जायफल जोड़ें ...

$(document).ready(function ()
{
    $(document).ajaxSend(
    function(event,request,settings)
    {
        var intercepted_success = settings.success;
        settings.success = function( a, b, c ) 
        {  
            if( request.responseText.indexOf( "<html>" ) > -1 )
                window.location = window.location;
            else
                intercepted_success( a, b, c );
        };
    });
});

मैं एचटीएमएल टैग की उपस्थिति की जांच करता हूं, लेकिन आप अपने लॉगिन पेज में जो भी अद्वितीय स्ट्रिंग मौजूद है, उसे खोजने के लिए आप indexOf को बदल सकते हैं ...


मैं बस पूरे पृष्ठ के लिए किसी भी AJAX अनुरोध पर लांच करना चाहता था। @SuperG मुझे शुरू कर दिया। यहां मैंने जो समाप्त किया है:

// redirect ajax requests that are redirected, not found (404), or forbidden (403.)
$('body').bind('ajaxComplete', function(event,request,settings){
        switch(request.status) {
            case 301: case 404: case 403:                    
                window.location.replace("http://mysite.tld/login");
                break;
        }
});

मैं विशेष रूप से अपने निर्णय के आधार पर कुछ http स्टेटस कोडों की जांच करना चाहता था। हालांकि, आप केवल सफलता के अलावा कुछ भी पाने के लिए AJAX त्रुटि से बंध सकते हैं (200 केवल शायद?) मैं बस लिखा होगा:

$('body').bind('ajaxError', function(event,request,settings){
    window.location.replace("http://mysite.tld/login");
}

मैंने इस प्रश्न को पढ़ा और रीडायरेक्ट को पारदर्शी रूप से संभालने वाले ब्राउजर से बचने के लिए प्रतिक्रिया स्थिति कोड को 278 पर सेट करने के बारे में बताया गया है। भले ही यह काम करता है, मैं थोड़ा असंतुष्ट था क्योंकि यह एक हैक का थोड़ा सा है।

चारों ओर खुदाई करने के बाद, मैंने इस दृष्टिकोण को हटा दिया और JSON उपयोग किया। इस मामले में, AJAX अनुरोधों के सभी प्रतिक्रियाओं में स्टेटस कोड 200 है और प्रतिक्रिया के शरीर में एक JSON ऑब्जेक्ट होता है जो सर्वर पर बनाया गया है। क्लाइंट पर जावास्क्रिप्ट फिर जेएसओएन ऑब्जेक्ट का उपयोग यह तय करने के लिए कर सकता है कि उसे क्या करना है।

मुझे तुम्हारी एक ही समस्या थी। मैं एक AJAX अनुरोध करता हूं जिसमें 2 संभावित प्रतिक्रियाएं होती हैं: वह जो ब्राउज़र को किसी नए पृष्ठ पर रीडायरेक्ट करता है और वह एक जो मौजूदा पृष्ठ पर मौजूदा HTML फ़ॉर्म को एक नए के साथ बदल देता है। ऐसा करने के लिए jquery कोड कुछ ऐसा दिखता है:

$.ajax({
    type: "POST",
    url: reqUrl,
    data: reqBody,
    dataType: "json",
    success: function(data, textStatus) {
        if (data.redirect) {
            // data.redirect contains the string URL to redirect to
            window.location.href = data.redirect;
        }
        else {
            // data.form contains the HTML for the replacement form
            $("#myform").replaceWith(data.form);
        }
    }
});

जेएसओएन ऑब्जेक्ट "डेटा" सर्वर पर 2 सदस्यों के लिए बनाया गया है: data.redirect और data.form। मैंने यह दृष्टिकोण बहुत बेहतर पाया।


मैंने इस मुद्दे को हल किया:

  1. प्रतिक्रिया में कस्टम हेडर जोड़ना:

    public ActionResult Index(){
        if (!HttpContext.User.Identity.IsAuthenticated)
        {
            HttpContext.Response.AddHeader("REQUIRES_AUTH","1");
        }
        return View();
    }
    
  2. ajaxSuccess ईवेंट में एक जावास्क्रिप्ट फ़ंक्शन बाध्य करना और यह देखने के लिए जांच करना कि हेडर मौजूद है या नहीं:

    $(document).ajaxSuccess(function(event, request, settings) {
        if (request.getResponseHeader('REQUIRES_AUTH') === '1') {
           window.location = '/';
        }
    });
    

मैंने इसे अपने login.php पेज में निम्नलिखित डालकर हल किया।

<script type="text/javascript">
    if (top.location.href.indexOf('login.php') == -1) {
        top.location.href = '/login.php';
    }
</script>

यह मेरे लिए काम किया:

success: function(data, textStatus, xhr) {

        console.log(xhr.status);
}

सफलता पर, AJAX को वही स्टेटस कोड मिलेगा जो ब्राउज़र सर्वर से प्राप्त होता है और इसे निष्पादित करता है।


यह समस्या तब एएसपी.नेट एमवीसी रीडायरेक्ट टॉक्शन विधि का उपयोग कर दिखाई दे सकती है। Div में प्रतिक्रिया प्रदर्शित करने वाले फॉर्म को रोकने के लिए आप $ .ajaxSetup के साथ असामान्य प्रतिक्रियाओं के लिए बस कुछ प्रकार के AJAX प्रतिक्रिया फ़िल्टर कर सकते हैं। अगर प्रतिक्रिया में एमवीसी रीडायरेक्शन होता है तो आप जेएस पक्ष पर इस अभिव्यक्ति का मूल्यांकन कर सकते हैं। नीचे जेएस के लिए उदाहरण कोड:

$.ajaxSetup({
    dataFilter: function (data, type) {
        if (data && typeof data == "string") {
            if (data.indexOf('window.location') > -1) {
                eval(data);
            }
        }
        return data;
    }
});

यदि डेटा है: "window.location = '/ acount / login'" फ़िल्टर से ऊपर होगा और डेटा को प्रदर्शित करने की बजाय पुनर्निर्देशन करने का मूल्यांकन करेगा।


सर्वलेट में आपको response.setStatus(response.SC_MOVED_PERMANENTLY); देना चाहिए .setStatus response.setStatus(response.SC_MOVED_PERMANENTLY); '301' xmlHttp स्थिति भेजने के लिए आपको एक पुनर्निर्देशन की आवश्यकता है ...

और $ .ajax फ़ंक्शन में आपको .toString() फ़ंक्शन का उपयोग नहीं करना चाहिए ..., बस

if (xmlHttp.status == 301) { top.location.href = 'xxxx.jsp'; }

समस्या यह है कि यह बहुत लचीला नहीं है, आप तय नहीं कर सकते कि आप कहां रीडायरेक्ट करना चाहते हैं ..

servlets के माध्यम से पुनर्निर्देशन सबसे अच्छा तरीका होना चाहिए। लेकिन मुझे अभी भी ऐसा करने का सही तरीका नहीं मिल रहा है।


Additionally you will probably want to redirect user to the given in headers URL. So finally it will looks like this:

$.ajax({
    //.... other definition
    complete:function(xmlHttp){
        if(xmlHttp.status.toString()[0]=='3'){
        top.location.href = xmlHttp.getResponseHeader('Location');
    }
});

UPD: Opps. Have the same task, but it not works. Doing this stuff. I'll show you solution when I'll find it.


I was having this problem on a django app I'm tinkering with (disclaimer: I'm tinkering to learn, and am in no way an expert). What I wanted to do was use jQuery ajax to send a DELETE request to a resource, delete it on the server side, then send a redirect back to (basically) the homepage. When I sent HttpResponseRedirect('/the-redirect/') from the python script, jQuery's ajax method was receiving 200 instead of 302. So, what I did was to send a response of 300 with:

response = HttpResponse(status='300')
response['Location'] = '/the-redirect/' 
return  response

Then I sent/handled the request on the client with jQuery.ajax like so:

<button onclick="*the-jquery*">Delete</button>

where *the-jquery* =
$.ajax({ 
  type: 'DELETE', 
  url: '/resource-url/', 
  complete: function(jqxhr){ 
    window.location = jqxhr.getResponseHeader('Location'); 
  } 
});

Maybe using 300 isn't "right", but at least it worked just like I wanted it to.

PS :this was a huge pain to edit on the mobile version of SO. Stupid ISP put my service cancellation request through right when I was done with my answer!


You can also hook XMLHttpRequest send prototype. This will work for all sends (jQuery/dojo/etc) with one handler.

I wrote this code to handle a 500 page expired error, but it should work just as well to trap a 200 redirect. Ready the wikipedia entry on XMLHttpRequest onreadystatechange about the meaning of readyState.

// Hook XMLHttpRequest
var oldXMLHttpRequestSend = XMLHttpRequest.prototype.send;

XMLHttpRequest.prototype.send = function() {
  //console.dir( this );

  this.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 500 && this.responseText.indexOf("Expired") != -1) {
      try {
        document.documentElement.innerHTML = this.responseText;
      } catch(error) {
        // IE makes document.documentElement read only
        document.body.innerHTML = this.responseText;
      }
    }
  };

  oldXMLHttpRequestSend.apply(this, arguments);
}




redirect