关于jquery中ajax请求在ie中报No Transport错误解决流程

来源:互联网 发布:mac怎么升级 编辑:程序博客网 时间:2024/06/03 20:51

关于jquery中ajax请求在ie中报No Transport错误解决流程

首先背景就是测试同学发现我们的网页在ie9中展示不正确,实际是所有异步的接口都没有执行。然后我就开始了苦逼的排查过程。我们所有异步接口都是使用jquery的ajax方法发出的,使用的jquery版本是1.11.0。

我最先定位到的是ajax方法返回status=0,statusText=No Transport。然后开始了我的查找问题之旅,我在网上所查出的资料都说这个是由于跨域造成的,加上$.support.cros=true就可以。但实际我们项目访问的接口并不属于跨域。所以虽然加上这个属性可以解决问题,但并没有找到根源。

于是我开始看jquery的源码,先定位了发生错误的代码段,先贴上报错点:

        // Get transport        transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );        // If no transport, we auto-abort        if ( !transport ) {            done( -1, "No Transport" );        } else {            jqXHR.readyState = 1;            // Send global event            if ( fireGlobals ) {                globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );            }            // Timeout            if ( s.async && s.timeout > 0 ) {                timeoutTimer = setTimeout(function() {                    jqXHR.abort("timeout");                }, s.timeout );            }            try {                state = 1;                transport.send( requestHeaders, done );            } catch ( e ) {                // Propagate exception as error if not done                if ( state < 2 ) {                    done( -1, e );                // Simply rethrow otherwise                } else {                    throw e;                }            }        }

此处transport =false。刚开始并不能完全看懂jquery源码,于是请教了我们公司的一位大神,在大神的指导下我开始排查为何transport =false。经过万能的断点调试,发现是由于下列代码中的options.crossDomain = true导致的不能进入此段正确发送请求的关键代码(具体的代码作用不作分析)。到此终于定位罪魁祸首是最初我为了在html页面可以直接访问api服务器而增加的crossDomain=true的设置(因为html和api服务器属于不同域名)。(此处并未结束,请继续往下看)

// Determine support propertiessupport.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );xhrSupported = support.ajax = !!xhrSupported;// Create transport if the browser can provide an xhrif ( xhrSupported ) {    jQuery.ajaxTransport(function( options ) {        // Cross domain only allowed if supported through XMLHttpRequest        if ( !options.crossDomain || support.cors ) {            var callback;            return {                send: function( headers, complete ) {                    var i,                        xhr = options.xhr(),                        id = ++xhrId;                    // Open the socket                    xhr.open( options.type, options.url, options.async, options.username, options.password );                    // Apply custom fields if provided                    if ( options.xhrFields ) {                        for ( i in options.xhrFields ) {                            xhr[ i ] = options.xhrFields[ i ];                        }                    }                    // Override mime type if needed                    if ( options.mimeType && xhr.overrideMimeType ) {                        xhr.overrideMimeType( options.mimeType );                    }                    // X-Requested-With header                    // For cross-domain requests, seeing as conditions for a preflight are                    // akin to a jigsaw puzzle, we simply never set it to be sure.                    // (it can always be set on a per-request basis or even using ajaxSetup)                    // For same-domain requests, won't change header if already provided.                    if ( !options.crossDomain && !headers["X-Requested-With"] ) {                        headers["X-Requested-With"] = "XMLHttpRequest";                    }                    // Set headers                    for ( i in headers ) {                        // Support: IE<9                        // IE's ActiveXObject throws a 'Type Mismatch' exception when setting                        // request header to a null-value.                        //                        // To keep consistent with other XHR implementations, cast the value                        // to string and ignore `undefined`.                        if ( headers[ i ] !== undefined ) {                            xhr.setRequestHeader( i, headers[ i ] + "" );                        }                    }                    // Do send the request                    // This may raise an exception which is actually                    // handled in jQuery.ajax (so no try/catch here)                    xhr.send( ( options.hasContent && options.data ) || null );                    // Listener                    callback = function( _, isAbort ) {                        var status, statusText, responses;                        // Was never called and is aborted or complete                        if ( callback && ( isAbort || xhr.readyState === 4 ) ) {                            // Clean up                            delete xhrCallbacks[ id ];                            callback = undefined;                            xhr.onreadystatechange = jQuery.noop;                            // Abort manually if needed                            if ( isAbort ) {                                if ( xhr.readyState !== 4 ) {                                    xhr.abort();                                }                            } else {                                responses = {};                                status = xhr.status;                                // Support: IE<10                                // Accessing binary-data responseText throws an exception                                // (#11426)                                if ( typeof xhr.responseText === "string" ) {                                    responses.text = xhr.responseText;                                }                                // Firefox throws an exception when accessing                                // statusText for faulty cross-domain requests                                try {                                    statusText = xhr.statusText;                                } catch( e ) {                                    // We normalize with Webkit giving an empty statusText                                    statusText = "";                                }                                // Filter status for non standard behaviors                                // If the request is local and we have data: assume a success                                // (success with no data won't get notified, that's the best we                                // can do given current implementations)                                if ( !status && options.isLocal && !options.crossDomain ) {                                    status = responses.text ? 200 : 404;                                // IE - #1450: sometimes returns 1223 when it should be 204                                } else if ( status === 1223 ) {                                    status = 204;                                }                            }                        }                        // Call complete if needed                        if ( responses ) {                            complete( status, statusText, responses, xhr.getAllResponseHeaders() );                        }                    };                    if ( !options.async ) {                        // if we're in sync mode we fire the callback                        callback();                    } else if ( xhr.readyState === 4 ) {                        // (IE6 & IE7) if it's in cache and has been                        // retrieved directly we need to fire the callback                        setTimeout( callback );                    } else {                        // Add to the list of active xhr callbacks                        xhr.onreadystatechange = xhrCallbacks[ id ] = callback;                    }                },                abort: function() {                    if ( callback ) {                        callback( undefined, true );                    }                }            };        }    });}

到此本来应该结束了,但并没有,虽然我增加了crossDomain=true的设置,但为何其他浏览器可以正常访问,而ie9不行呢。我继续调试代码,最终发现其他浏览器上述代码中support.cors = true,而ie9下这个属性等于false。从上述代码中也可以看到,这个属性的判断来自于support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ),其中xhrSupported= new window.XMLHttpRequest(),ie9中XMLHttpRequest没有withCredentials属性。也就是说这个问题是由于我的乱用属性加上各浏览器兼容性问题而导致的。

0 0
原创粉丝点击