Задача:
В расширении идет отправка данных через XMLHttpRequest на сервер.
Возможны 2 варианта:
1) Сервер выставляет статус 200, и выдает ответ.
2) Сервер выставляет статус 302, перенаправляет через заголовок Location на другую страницу, которая, выставляя статус 200, уже выдает ответ.

Как отловить это перенаправление во втором случае?

Пробовал делать через onreadystatechange, но readyState принимает значение 2 (когда доступен статус) только при ответе страницы, на которую идет перенаправление.

Как же отследить появление первого ответа, и узнать, было ли перенаправление?

В идеале, хотелось бы достичь следующего:
отправить запрос, получить заголовки со статусом 302, и прервать запрос, чтобы данные дальше не передавались и не "кушали" лишний трафик.

может в респонсхидерах порыться?

Rion
Это-то понятно. Весь вопрос в том, как их получить. Когда идет запрос, и статус ответа 200, всё понятно - элементарно. А вот когда идёт перенаправление через статус 302, тогда не выходит, т.к. headers и статус становятся доступны когда readyState принимает значение 2, а это происходит уже после получения заголовков ответа со статусом 200. Получается, что факт перенаправления никак не прослеживается.

Yan пишет

Получается, что факт перенаправления никак не прослеживается.

Да, в Gecko это не отслеживается.

Mash

Да, в Gecko это не отслеживается.

Жаль.
Спасибо за инфу.

...в Gecko это не отслеживается.

При использовании асинхронного вызова. Может, можно "отследить", используя синхронный вызов.

А если не использовать XMLHttpRequest ? В прототипе bookmarksFavIconLoadListener есть метод onRedirect (файл bookmarks.js), используется интерфейс nsIChannel.

Синхронный вызов не подходит из-за "подвисания" интерфейса.

Вот что я предлагаю. Если это расширение для Firefox, то

Выделить код

Код:

// предварительные определения
function getContent (aReq, aCont)
{
    var st;
    aReq. cancel (st);
    if (this. redFlag)
    {
        // обрабатываем редирект
    }
    else
    {
        var x = new XMLHttpRequest;
        ... 
    }
}

function chanListener (a, b, c) { this. redFlag = false; }
chanListener. prototype = bookmarksFavIconLoadListener. prototype;
chanListener. prototype. onRedirect = function (aCh, aNCh) { this. redFlag = true; }
chanListener.prototype. onDataAvailable = function (aReq, aCont, aIS, aOff, aC) {}
chanListener. prototype. onStartRequest = getContent;

// собственно обработка
var kIOContractID = "@mozilla.org/network/io-service;1";
var kIOIID = Components. interfaces. nsIIOService;
var IOSVC = Components. classes[kIOContractID]. getService(kIOIID);
var chan = IOSVC. newChannel ("http://gmail.google.com/gmail", null, null);
var listener = new chanListener ("http://gmail.google.com/gmail", "", chan);
chan. notificationCallbacks = listener;
chan. asyncOpen (listener, null);

а если нет - примерно то же самое, только без prototype и с полным определением методов chanListener ("подсмотреть" можно в bookmarks.js)

Придумалось. Позволяет отловить первый редирект. Делюсь:

Выделить код

Код:

with (Components)
with (interfaces)
function myXMLHttpRequest ()
{
    var mxhr = this;
    var request, reqId;
    var observer =
    {
        observe: function (subject, topic, data)
        {
            subject. QueryInterface (nsIHttpChannel);
            if ((reqId == subject. notificationCallbacks. requestId) && mxhr. onresponse)
            {
                try
                {
                    mxhr. onresponse (subject);
                } catch (e) {}
            }
        }
    }
    function removeObserver ()
    {
        var rdfService = classes ["@mozilla.org/rdf/rdf-service;1"].
                         getService (nsIRDFService);
        rdfService. UnregisterResource (reqId);
        try
        {
            var observerService = classes ["@mozilla.org/observer-service;1"].
                                  getService (nsIObserverService);
            observerService. removeObserver (observer, "http-on-examine-response");
        } catch (e) {}
    }
    function onError () 
    {
        removeObserver ();
        if (mxhr. onerror)
            mxhr. onerror ();
    }
    function onLoad ()
    {
        removeObserver ();
        if (mxhr. onload)
            mxhr. onload ();
    }
    this. open = function (method, url, asyncFlag)
    {
        var rdfService = classes ["@mozilla.org/rdf/rdf-service;1"].
                         getService (nsIRDFService);
        reqId = rdfService. GetAnonymousResource (). Value;
        request = new XMLHttpRequest ();
        request. open (method, url, asyncFlag);
        request. requestId = reqId;
        request. onerror = onError;
        request. onload = onLoad;
    }
    this. send = function (message)
    {
        if (mxhr. onresponse)
        {
            var observerService = classes ["@mozilla.org/observer-service;1"].
                                  getService (nsIObserverService);
            observerService. addObserver (observer, "http-on-examine-response", false);
        }
        request. send (message);
    }
    this. setRequestHeader = function (name, value)
    {
        request. setRequestHeader (name, value);
    }
}


// использование
var req = new myXMLHttpRequest ();
req. open ("GET", "http://www.google.com", true);
req. onresponse = function (httpChannel)
{
    print (httpChannel. responseStatus);
    // if (httpChannel. responseStatus == 302) // redirect
    // {
    //     . . .
    // }
}
req. send ();