jQuery ajax (jsonp) bỏ qua thời gian chờ và không kích hoạt sự kiện lỗi


89

Để thêm một số xử lý lỗi cơ bản, tôi muốn viết lại một đoạn mã sử dụng $ .getJSON của jQuery để lấy một số ảnh từ Flickr. Lý do của việc này là $ .getJSON không cung cấp khả năng xử lý lỗi hoặc làm việc với thời gian chờ.

Vì $ .getJSON chỉ là một trình bao bọc xung quanh $ .ajax, tôi đã quyết định viết lại điều này và gây ngạc nhiên bất ngờ, nó hoạt động hoàn hảo.

Bây giờ niềm vui bắt đầu mặc dù. Khi tôi cố tình gây ra lỗi 404 (bằng cách thay đổi URL) hoặc khiến mạng hết thời gian chờ (do không được kết nối với các mạng xen kẽ), sự kiện lỗi hoàn toàn không kích hoạt. Tôi bối rối không biết mình đang làm gì sai. Giúp đỡ được nhiều đánh giá cao.

Đây là mã:

$(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);
        }
    });

});

Tôi muốn nói thêm rằng câu hỏi này đã được hỏi khi jQuery ở phiên bản 1.4.2

Câu trả lời:


86

jQuery 1.5 trở lên hỗ trợ tốt hơn cho việc xử lý lỗi với các yêu cầu JSONP. Tuy nhiên, bạn cần sử dụng $.ajaxphương pháp thay thế $.getJSON. Đối với tôi, điều này hoạt động:

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

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

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

Thời gian chờ dường như thực hiện thủ thuật và gọi trình xử lý lỗi, khi không có yêu cầu thành công nào sau 10 giây.

Tôi cũng đã làm một bài đăng blog nhỏ về chủ đề này.


23
Tôi thực sự khó chịu ngay bây giờ vì tôi đã đối đầu với sự cố này trong 2 ngày và phải mất một số tìm kiếm khó hiểu trên StackOverflow để tìm ra tôi phải thêm thời gian chờ cho một yêu cầu tên miền chéo để khắc phục lỗi. Làm thế nào điều này có thể không được đề cập trong tài liệu jQuery? Yêu cầu jsonp tên miền chéo có thực sự không phổ biến không? Trong mọi trường hợp, cảm ơn bạn, cảm ơn bạn, cảm ơn bạn. +1
chrixian

Với giải pháp này, tôi không thể lấy mã trạng thái, thay vào đó tôi nhận được "thời gian chờ". Vì vậy, tôi không thể biết lỗi thực sự là gì, và không thể xử lý tài sản đó.
Tarlog

10
@Tarlog: đó là hợp lý. Các yêu cầu JSONP không phải là các yêu cầu Ajax gốc, chúng chỉ đơn giản là <script>các thẻ Javascript được chèn động. Do đó, điều duy nhất bạn có thể biết là yêu cầu không thành công, không phải mã trạng thái. Nếu bạn muốn nhận mã trạng thái, bạn cần sử dụng các yêu cầu Ajax truyền thống hoặc các kỹ thuật miền chéo khác.
Husky

1
Như @Husky đã nói, bạn không thể có mã trạng thái với JSONP và tôi tin rằng đó là lý do tại sao bạn nên cố gắng tránh nó. Cách duy nhất để nhận lỗi là đặt thời gian chờ. Điều này nên được giải thích rõ hơn trong tài liệu jQuery (cũng như nhiều thứ khác).
Alejandro García Iglesias

67

Đây là một hạn chế đã biết với việc triển khai jsonp gốc trong jQuery. Văn bản dưới đây là từ IBM DeveloperWorks

JSONP là một kỹ thuật rất mạnh để xây dựng các mashup, nhưng thật không may, nó không phải là phương pháp chữa trị cho tất cả các nhu cầu giao tiếp giữa các miền của bạn. Nó có một số nhược điểm cần được xem xét nghiêm túc trước khi cam kết nguồn lực phát triển. Đầu tiên và quan trọng nhất, không có lỗi xử lý cho các cuộc gọi JSONP. Nếu tính năng chèn tập lệnh động hoạt động, bạn sẽ được gọi; nếu không, không có gì xảy ra. Nó chỉ âm thầm thất bại. Ví dụ: bạn không thể bắt được lỗi 404 từ máy chủ. Bạn cũng không thể hủy bỏ hoặc bắt đầu lại yêu cầu. Tuy nhiên, bạn có thể hết thời gian chờ sau một khoảng thời gian hợp lý. (Các phiên bản jQuery trong tương lai có thể có tính năng hủy bỏ các yêu cầu JSONP.)

Tuy nhiên, có một trình cắm jsonp có sẵn trên GoogleCode hỗ trợ xử lý lỗi. Để bắt đầu, chỉ cần thực hiện các thay đổi sau đối với mã của bạn.

Bạn có thể tải xuống hoặc chỉ cần thêm tham chiếu tập lệnh vào trình cắm.

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

Sau đó, sửa đổi lệnh gọi ajax của bạn như được hiển thị bên dưới:

$(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);
        }
    });
});

Cảm ơn câu trả lời của bạn José! Việc triển khai hạn chế jsonp gốc trong jQuery là lý do khiến tôi sử dụng $ .ajax. Tuy nhiên, sau đó có vẻ như vấn đề không phải là $ .getJSON là một trình bao bọc xung quanh $ .ajax mà là dataType: jsonp. Đúng không?
Matijs

Đã không có thời gian cho đến ngày hôm nay. Tuy nhiên, nó không hoạt động. Tôi đang gặp lỗi, nhưng đó là về nó. Tôi không biết lỗi gì vì errorThrown là không xác định. Hiện tại, tôi sẽ gắn bó với $ .ajax và thiếu các thông báo lỗi. Javascript là một lớp bổ sung trên đầu trang web đối với tôi. Nếu Flickr không hoạt động hoặc gửi thông báo lỗi, chúng tôi sẽ phải sống với nó ngay bây giờ :) Cảm ơn đề xuất của bạn.
Matijs

Vì vậy, về cơ bản đề xuất của José bằng cách sử dụng plugin jsonp, nếu được thực hiện đúng, sẽ hoạt động. Tuy nhiên, bây giờ tôi sẽ gắn bó với trình bao bọc json cơ bản cho jQuery.
Matijs

Điều này làm việc rực rỡ cho tôi một lần tôi đã đâm vào tường với built-in hạn chế của xử lý lỗi jsonp của
Jeremy Frey

7
Một nhà phát triển khác đã được lưu bằng mẹo này. Cảm ơn!
chesterbr

12

Một giải pháp nếu bạn gặp khó khăn với jQuery 1.4:

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

2
chỉ là một nhận xét, đó là một giải pháp hợp lệ cho những người mắc kẹt với 1.4, nhưng hãy đặt biến thời gian chờ của bạn đủ cao, để bạn không gặp vấn đề với các dịch vụ web chậm :). Ví dụ: nếu bạn đặt nó thành một giây, bạn có thể hiểu ý tôi là, lỗi gọi lại sẽ được kích hoạt, trong khi sau 1 giây đó, cuộc gọi của bạn vẫn được tìm nạp và gọi hàm thành công. vì vậy chỉ cần lưu ý đặt nó đủ cao hợp lý
Sander

@Sander chức năng thành công thậm chí có thể được gọi nếu bạn nhận được câu trả lời sau 10 giây với thời gian chờ là 5 giây. Gọi .abort()bằng jqXHR đang chờ xử lý sau một khoảng thời gian chờ có thể là cách tốt hơn.
Matijs

8

Đây có thể là một hạn chế "đã biết" của jQuery; tuy nhiên, nó dường như không được ghi chép đầy đủ. Tôi đã dành khoảng 4 giờ hôm nay để cố gắng tìm hiểu lý do tại sao thời gian chờ của tôi không hoạt động.

Tôi đã chuyển sang jquery.jsonp và nó hoạt động như một sự quyến rũ. Cảm ơn bạn.


2

Có vẻ như đã được giải quyết kể từ jQuery 1.5. Tôi đã thử mã ở trên và tôi nhận được cuộc gọi lại.

Tôi nói "dường như là" bởi vì tài liệu về lỗi gọi lại cho jQuery.ajax () vẫn có lưu ý sau:

Lưu ý: Trình xử lý này không được gọi cho các yêu cầu tập lệnh miền chéo và JSONP.


1

Bạn có thể tìm thấy plugin jquery-jsonp jQuery trong câu trả lời của Jose Basilio trên GitHub .

Thật không may, tài liệu hơi khó hiểu, vì vậy tôi đã cung cấp một ví dụ đơn giản:

    $.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"
        }
    });

Quan trọng Bao gồm callbackParameter trong lệnh gọi $ .jsonp () nếu không, tôi thấy rằng hàm gọi lại không bao giờ được đưa vào chuỗi truy vấn của lệnh gọi dịch vụ (hiện tại kể từ phiên bản 2.4.0 của jquery-jsonp).

Tôi biết câu hỏi này đã cũ, nhưng vấn đề xử lý lỗi khi sử dụng JSONP vẫn chưa được 'giải quyết'. Hy vọng rằng bản cập nhật này sẽ hỗ trợ những người khác vì câu hỏi này được xếp hạng hàng đầu trong Google về "xử lý lỗi jquery jsonp".


thoải mái tìm kiếm, và tuyệt vời chủ đề này vẫn còn sống sau ba năm ...
Matijs

1

Điều gì về nghe sự kiện lỗi của kịch bản? Tôi đã gặp sự cố này và đã giải quyết nó bằng cách vá phương thức của jquery nơi thẻ tập lệnh được tạo. Đây là đoạn mã thú vị:

// 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;
}

Bạn nghĩ gì về giải pháp này? Nó có khả năng gây ra sự cố tương thích không?

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.