jQuery ajax (jsonp) ละเว้นการหมดเวลาและไม่เริ่มเหตุการณ์ข้อผิดพลาด


89

ในการเพิ่มการจัดการข้อผิดพลาดพื้นฐานฉันต้องการเขียนโค้ดใหม่ที่ใช้ $ .getJSON ของ jQuery เพื่อดึงภาพถ่ายบางส่วนจาก Flickr เหตุผลในการทำเช่นนี้คือ $ .getJSON ไม่มีการจัดการข้อผิดพลาดหรือทำงานกับการหมดเวลา

เนื่องจาก $ .getJSON เป็นเพียงกระดาษห่อหุ้มที่มีราคาประมาณ $ .ajax ฉันจึงตัดสินใจเขียนสิ่งนี้ใหม่และสร้างความประหลาดใจให้กับมันจึงทำงานได้อย่างไม่มีที่ติ

ตอนนี้ความสนุกเริ่มต้นขึ้น เมื่อฉันจงใจทำให้เกิด 404 (โดยการเปลี่ยน URL) หรือทำให้เครือข่ายหมดเวลา (โดยไม่เชื่อมต่อกับอินเตอร์เว็บ) เหตุการณ์ข้อผิดพลาดจะไม่เริ่มทำงานเลย ฉันสูญเสียสิ่งที่ฉันทำผิด ความช่วยเหลือเป็นที่ชื่นชมมาก

นี่คือรหัส:

$(document).ready(function(){

    // var jsonFeed = "http://api.flickr.com/services/feeds/photos_public.gne"; // correct URL
    var jsonFeed = "http://api.flickr.com/services/feeds/photos_public.gne_______"; // this should throw a 404

    $.ajax({
        url: jsonFeed,
        data: { "lang" : "en-us",
                "format" : "json",
                "tags" : "sunset"
        },
        dataType: "jsonp",
        jsonp: "jsoncallback",
        timeout: 5000,
        success: function(data, status){
            $.each(data.items, function(i,item){
                $("<img>").attr("src", (item.media.m).replace("_m.","_s."))
                          .attr("alt", item.title)
                          .appendTo("ul#flickr")
                          .wrap("<li><a href=\"" + item.link + "\"></a></li>");
                if (i == 9) return false;
            });
        },
        error: function(XHR, textStatus, errorThrown){
            alert("ERREUR: " + textStatus);
            alert("ERREUR: " + errorThrown);
        }
    });

});

ฉันต้องการเพิ่มว่าคำถามนี้ถูกถามเมื่อ jQuery เป็นเวอร์ชัน 1.4.2

คำตอบ:


86

jQuery 1.5 ขึ้นไปมีการรองรับการจัดการข้อผิดพลาดกับคำขอ JSONP ที่ดีกว่า แต่คุณจำเป็นต้องใช้วิธีการแทน$.ajax $.getJSONสำหรับฉันสิ่งนี้ได้ผล:

var req = $.ajax({
    url : url,
    dataType : "jsonp",
    timeout : 10000
});

req.success(function() {
    console.log('Yes! Success!');
});

req.error(function() {
    console.log('Oh noes!');
});

การหมดเวลาดูเหมือนจะทำเคล็ดลับและเรียกตัวจัดการข้อผิดพลาดเมื่อไม่มีคำขอที่สำเร็จหลังจาก 10 วินาที

ฉันได้โพสต์บล็อกเล็ก ๆ น้อย ๆเกี่ยวกับเรื่องนี้เช่นกัน


23
ตอนนี้ฉันรู้สึกรำคาญมากที่ได้เผชิญหน้ากับปัญหานี้เป็นเวลา 2 วันและต้องใช้การค้นหาที่คลุมเครือใน StackOverflow เพื่อค้นหาว่าฉันต้องเพิ่มระยะหมดเวลาในคำขอข้ามโดเมนเพื่อให้ข้อผิดพลาดเริ่มทำงาน จะไม่กล่าวถึงสิ่งนี้ในเอกสาร jQuery ได้อย่างไร คำขอ jsonp ข้ามโดเมนเป็นเรื่องผิดปกติหรือไม่? ไม่ว่าในกรณีใด ๆ ขอบคุณขอบคุณขอบคุณ +1
chrixian

ด้วยวิธีแก้ปัญหานี้ฉันไม่สามารถรับรหัสสถานะได้ฉันจะได้รับ "หมดเวลา" แทน ดังนั้นฉันจึงไม่สามารถรู้ได้ว่าอะไรคือข้อผิดพลาดที่แท้จริงและไม่สามารถจัดการกับคุณสมบัตินี้ได้
Tarlog

10
@ Tarlog: นั่นเป็นเหตุผล คำขอ JSONP ไม่ใช่คำขอ Ajax ดั้งเดิม แต่เป็นเพียง<script>แท็กJavascript ที่แทรกแบบไดนามิก สิ่งเดียวที่คุณสามารถทราบได้คือคำขอล้มเหลวไม่ใช่รหัสสถานะคืออะไร หากคุณต้องการรับรหัสสถานะคุณต้องใช้คำขอ Ajax แบบดั้งเดิมหรือเทคนิคข้ามโดเมนอื่น ๆ
Husky

1
ดังที่ @Husky กล่าวคุณไม่สามารถมีรหัสสถานะกับ JSONP ได้และฉันเชื่อว่านั่นเป็นเหตุผลที่คุณควรพยายามหลีกเลี่ยง วิธีเดียวในการรับข้อผิดพลาดคือการหมดเวลา สิ่งนี้ควรอธิบายได้ดีกว่าในเอกสาร jQuery (เช่นเดียวกับสิ่งอื่น ๆ อีกมากมาย)
Alejandro García Iglesias

67

นี่เป็นข้อ จำกัด ที่ทราบกันดีในการใช้งาน jsonp ดั้งเดิมใน jQuery ข้อความด้านล่างมาจากIBM DeveloperWorks

JSONP เป็นเทคนิคที่มีประสิทธิภาพมากในการสร้างการผสม แต่น่าเสียดายที่ไม่ใช่วิธีการรักษาทั้งหมดสำหรับความต้องการการสื่อสารข้ามโดเมนทั้งหมดของคุณ มีข้อบกพร่องบางประการที่ต้องนำมาพิจารณาอย่างจริงจังก่อนที่จะส่งทรัพยากรเพื่อการพัฒนา ก่อนอื่นไม่มีการจัดการข้อผิดพลาดสำหรับการเรียก JSONP หากการแทรกสคริปต์แบบไดนามิกใช้งานได้คุณจะถูกเรียก ถ้าไม่ไม่มีอะไรเกิดขึ้น มันล้มเหลวอย่างเงียบ ๆ ตัวอย่างเช่นคุณไม่สามารถตรวจจับข้อผิดพลาด 404 จากเซิร์ฟเวอร์ได้ และคุณไม่สามารถยกเลิกหรือเริ่มคำขอใหม่ได้ อย่างไรก็ตามคุณสามารถหมดเวลาได้หลังจากรอเป็นเวลาพอสมควร (เวอร์ชัน jQuery ในอนาคตอาจมีคุณลักษณะยกเลิกสำหรับคำขอ JSONP)

อย่างไรก็ตามมีปลั๊กอิน jsonp ในGoogleCodeที่ให้การสนับสนุนสำหรับการจัดการข้อผิดพลาด ในการเริ่มต้นเพียงทำการเปลี่ยนแปลงต่อไปนี้กับรหัสของคุณ

คุณสามารถดาวน์โหลดหรือเพิ่มการอ้างอิงสคริปต์ไปยังปลั๊กอิน

<script type="text/javascript" 
     src="http://jquery-jsonp.googlecode.com/files/jquery.jsonp-1.0.4.min.js">
</script>

จากนั้นแก้ไขการโทร ajax ของคุณดังที่แสดงด้านล่าง:

$(function(){
    //var jsonFeed = "http://api.flickr.com/services/feeds/photos_public.gne"; // correct URL
    var jsonFeed = "http://api.flickr.com/services/feeds/photos_public.gne_______"; // this should throw a 404  
    $.jsonp({
        url: jsonFeed,
        data: { "lang" : "en-us",
                "format" : "json",
                "tags" : "sunset"
        },
        dataType: "jsonp",
        callbackParameter: "jsoncallback",
        timeout: 5000,
        success: function(data, status){
            $.each(data.items, function(i,item){
                $("<img>").attr("src", (item.media.m).replace("_m.","_s."))
                          .attr("alt", item.title)
                          .appendTo("ul#flickr")
                          .wrap("<li><a href=\"" + item.link + "\"></a></li>");
                if (i == 9) return false;
            });
        },
        error: function(XHR, textStatus, errorThrown){
            alert("ERREUR: " + textStatus);
            alert("ERREUR: " + errorThrown);
        }
    });
});

ขอบคุณสำหรับคำตอบJosé! การใช้ jsonp แบบ จำกัด ใน jQuery เป็นเหตุผลที่ฉันใช้ $ .ajax แทน อย่างไรก็ตามดูเหมือนว่าปัญหาไม่ได้อยู่ที่ $ .getJSON เป็น wrapper ที่อยู่ที่ $ .ajax แต่เป็น dataType: jsonp ถูกต้องหรือไม่
Matijs

ยังไม่มีเวลาจนถึงวันนี้ อย่างไรก็ตามมันไม่ได้ผล ฉันได้รับข้อผิดพลาด แต่ก็เกี่ยวกับเรื่องนี้ ฉันไม่รู้ว่า errorThrown คืออะไรไม่ได้กำหนด ตอนนี้ฉันจะติด $ .ajax และไม่มีข้อความแสดงข้อผิดพลาด Javascript เป็นเลเยอร์พิเศษที่ด้านบนของหน้าเว็บสำหรับฉัน หาก Flickr หยุดทำงานหรือส่งข้อความแสดงข้อผิดพลาดเราจะต้องดำเนินการต่อไปก่อน :) ขอบคุณสำหรับคำแนะนำของคุณ
Matijs

โดยพื้นฐานแล้วคำแนะนำของJoséโดยใช้ปลั๊กอิน jsonp ควรใช้งานได้หากทำอย่างถูกต้อง อย่างไรก็ตามตอนนี้ฉันจะใช้กระดาษห่อ json พื้นฐานสำหรับ jQuery
Matijs

สิ่งนี้ใช้ได้ผลดีสำหรับฉันเมื่อฉันชนกำแพงด้วยข้อ จำกัด ในตัวของการจัดการข้อผิดพลาดของ jsonp
Jeremy Frey

7
นักพัฒนารายอื่นบันทึกไว้โดยเคล็ดลับนี้ ขอบคุณ!
chesterbr

12

วิธีแก้ปัญหาหากคุณติด jQuery 1.4:

var timeout = 10000;
var id = setTimeout( errorCallback, timeout );
$.ajax({
    dataType: 'jsonp',
    success: function() {
        clearTimeout(id);
        ...
    }
});

2
เพียงแค่คำพูดเป็นวิธีแก้ปัญหาที่ถูกต้องสำหรับผู้ที่ติด 1.4 แต่ตั้งค่าตัวแปรการหมดเวลาของคุณให้สูงพอดังนั้นคุณจะไม่มีปัญหากับบริการเว็บที่ช้า :) ตัวอย่างเช่นหากคุณตั้งค่าเป็นหนึ่งวินาทีคุณจะเห็นว่าฉันหมายถึงอะไรการเรียกกลับข้อผิดพลาดจะถูกทริกเกอร์ในขณะที่หลังจากนั้น 1 วินาทีสายของคุณยังคงถูกดึงและเรียกใช้ฟังก์ชันความสำเร็จ ดังนั้นโปรดจำไว้ว่าให้สูงพอสมควร
Sander

@Sander ฟังก์ชั่นความสำเร็จสามารถเรียกได้หากคุณได้รับคำตอบหลังจาก 10 วินาทีโดยมีระยะเวลา 5 วินาที การเรียก.abort()ใช้ jqXHR ที่รอดำเนินการหลังจากช่วงหมดเวลาอาจเป็นวิธีที่ดีกว่า
Matijs

8

นี่อาจเป็นข้อ จำกัด "ที่ทราบ" ของ jQuery อย่างไรก็ตามดูเหมือนจะไม่ได้รับการบันทึกไว้เป็นอย่างดี วันนี้ฉันใช้เวลาประมาณ 4 ชั่วโมงเพื่อทำความเข้าใจว่าเหตุใดการหมดเวลาของฉันจึงไม่ทำงาน

ฉันเปลี่ยนมาใช้jquery.jsonpและมันใช้งานได้ดี ขอขอบคุณ.


2

ดูเหมือนว่าจะได้รับการแก้ไขเมื่อ jQuery 1.5 ฉันได้ลองใช้รหัสด้านบนและได้รับการติดต่อกลับ

ฉันพูดว่า "น่าจะเป็น" เนื่องจากเอกสารของการเรียกกลับข้อผิดพลาดสำหรับjQuery.ajax ()ยังคงมีหมายเหตุต่อไปนี้:

หมายเหตุ: ตัวจัดการนี้ไม่ถูกเรียกสำหรับสคริปต์ข้ามโดเมนและคำขอ JSONP


1

jQuery-jsonp jQuery ปลั๊กอินที่กล่าวถึงในโฮเซลิโอของ คำตอบขณะนี้คุณสามารถพบได้บนGitHub

น่าเสียดายที่เอกสารประกอบค่อนข้างสปาร์ตันดังนั้นฉันจึงให้ตัวอย่างง่ายๆ:

    $.jsonp({
        cache: false,
        url: "url",
        callbackParameter: "callback",
        data: { "key" : "value" },
        success: function (json, textStatus, xOptions) {
            // handle success - textStatus is "success"   
        },
        error: function (xOptions, textStatus) {
            // handle failure - textStatus is either "error" or "timeout"
        }
    });

สิ่งสำคัญ รวม callbackParameter ในการเรียก $ .jsonp () มิฉะนั้นฉันพบว่าฟังก์ชันการโทรกลับไม่เคยถูกแทรกเข้าไปในสตริงการสืบค้นของการเรียกใช้บริการ (ปัจจุบันเป็นเวอร์ชัน 2.4.0 ของ jquery-jsonp)

ฉันรู้ว่าคำถามนี้เก่า แต่ปัญหาของการจัดการข้อผิดพลาดโดยใช้ JSONP ยังไม่ได้รับการ 'แก้ไข' หวังว่าการอัปเดตนี้จะช่วยผู้อื่นได้เนื่องจากคำถามนี้ติดอันดับสูงสุดใน Google สำหรับ "jquery jsonp error management"


พบที่ดีและน่าอัศจรรย์กระทู้นี้ยังคงมีชีวิตอยู่หลังจากผ่านไปสามปี…
Matijs

1

สิ่งที่เกี่ยวกับการฟังเหตุการณ์ onerror ของสคริปต์? ฉันมีปัญหานี้และแก้ไขได้โดยการแก้ไขวิธีการของ jquery ที่สร้างแท็กสคริปต์ นี่คือบิตที่น่าสนใจของโค้ด:

// Attach handlers for all browsers
script.onload = script.onreadystatechange = function( _, isAbort ) {

    if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {

        cleanup();

        // Callback if not abort
        if ( !isAbort ) {
            callback( 200, "success" );
        }
    }
};

/* ajax patch : */
script.onerror = function(){
    cleanup();

    // Sends an inappropriate error, still better than nothing
    callback(404, "not found");
};

function cleanup(){
    // Handle memory leak in IE
    script.onload = script.onreadystatechange = null;

    // Remove the script
    if ( head && script.parentNode ) {
        head.removeChild( script );
    }

    // Dereference the script
    script = undefined;
}

คุณคิดอย่างไรกับการแก้ปัญหานี้? มีแนวโน้มที่จะทำให้เกิดปัญหาความเข้ากันได้หรือไม่?

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.