How to callback a function on 404 in JSON ajax request with jQuery?

梦想的初衷 提交于 2019-11-27 23:30:23
Dustin Laine
$.ajax({
    url: 'http://twitter.com/status/user_timeline/jksqdlmjmsd.json?count=3&callback=jsonp1269278524295&_=1269278536697',
    dataType: "json",
    success: function(data) {
        alert('success');
    },
    error: function(data) {
        alert('error');
    },
    complete: function(xhr, data) {
        if (xhr.status != 0)
             alert('success');
        else
             alert('fail');
    }
})

With your configuration jQuery uses jsonp to transport the data. This works by dynamically inserting a script element and setting the URL to the specified value. The data returned by the server is then evaluated as JavaScript - usually calling the provided callback. If the server returns a 404, the contents is obviously no JavaScript and the callback is never called. Some browsers support error handlers on the script tag, which are called in these situations. Unfortunately IE doens't support this. The best way to detect an error is to rely on a timeout.

In your case you should specify an additional timeout option, which causes the error handler to be called if the callback wasn't called in time (which would be the case for a 404 response).

$.ajax({
  url: 'http://my_url',
  timeout: 2000, // 2 seconds timeout
  dataType: "json",
  success: function(data){
    alert('success');
  },
  error: function(data){
    alert('error');
  },
  complete: function(data) {
    alert('complete')
  }
});

If you want to handle errors when accessing the Twitter API with Javascript and jsonp you need to include the parameter suppress_response_codes in your request. This makes all responses from the Twitter API respond with a 200 OK response and include a error. Then you need to check if the response includes the error parameter or not.

$.ajax({
  url: "https://api.twitter.com/1/users/show.json",
  dataType: 'jsonp',
  jsonp: "callback",
  data: {
    screen_name: "simongate1337",
    suppress_response_codes: true // <- Important part
  },
  success: function(data) {
    if(data.error) {
      console.log("ERROR: "+data.error);
    } else {
      console.log("Success, got user " + data.screen_name);
    }
  }
});
Peter Rader

Use the statusCode-Option

$.ajax({
    url: 'http://my_url',
    dataType: "json",
    statusCode: {
        404: function() {
            alert("I could not find the information you requested.");
        }
    },
    success: function(data) {
      alert('success');
    },
    error: function(data) {
      alert('error');
    },
    complete: function(data) {
      alert('complete');
    }
})

Do not you think that the problem is not with the dataType but with cross-domain requests that you are not allowed to make?

The code below works as expected when you request data from the same domain and does not when you are making cross-domain requests:

function handle404(xhr){
    alert('404 not found');
}

function handleError(xhr, status, exc) {
     // 0 for cross-domain requests in FF and security exception in IE 
    alert(xhr.status);
    switch (xhr.status) {
        case 404:
            handle404(xhr);
            break;
    }
}

function dumbRequest() {
    var url = 'http://twitter.com/status/user_timeline/jksqdlmjmsd.json?count=3&callback=jsonp1269278524295&_=1269278536697';
    url = 'http://twitter.com/';    
    url = '/mydata.json';    
//    url = 'mydata.json';    
    $.ajax(
        {url: url,
         dataType: 'json',
         error: handleError}
    );
}

Is it simply because the dataType is set to "json"? If so, try changing it to text and evaluate the JSON yourself:

$.ajax({
    url: 'http://twitter.com/status/user_timeline/jksqdlmjmsd.json?count=3&callback=jsonp1269278524295&_=1269278536697',
    dataType: 'text',
    success: function(data, status, xmlHttp) {
        try {
            data = eval('(' + data + ')');
            alert('success');
        } catch (e) {
            alert('json parse error');
        }
    },
    error: function(xmlHttp, status, error) {
        alert('error');
    },
    complete: function(xmlHttp, status) {
        alert('complete');
    }
});

Are you aware that even though the HTTP status is 404, the actual body is valid JSON? For instance, this link has the following JSON:

jsonp1269278524295({"request":"/status/user_timeline/jksqdlmjmsd.json?count=3&callback=jsonp1269278524295&_=1269278536697","error":"Not found"})

As such, you should check if your data has the error property within your normal callback function.

UPDATE: apparently, even though the actual content of the page is valid JSON, the browser (I checked in Firefox) is not executing it, most likely because it is a 404. Because jQuery has to add a script element (because of the cross-domain issue), its JSONP wrapper is never called, and as a consequence, neither are your callbacks.

So, in short, I don't think there is a way to deal with this without manually adding that script element and checking if your pre-defined callback function has been called afterwards.

Mark

Just faced the same issue, and saw another question mentioned that jQuery-JSONP (jQuery Plugin) supports catching 404 errors or as they describe: "error recovery in case of network failure or ill-formed JSON responses"

And it works perfect :)

Here is my (simplified) code for fetching details about a YouTube video via JSONP:

$.jsonp(
{
    url: "https://gdata.youtube.com/feeds/api/videos/ee925OTFBCA",
    callbackParameter: "callback",
    data: 
    {
        alt: "jsonc-in-script",
        v: "2"
    },
    success: function(json, textStatus) 
    { 
        console.log("WEEEEEEEE!"); 
    },
    error: function(xOptions, textStatus) 
    {
        console.error(arguments);
    }
});

Here's how I deal with this. I check the returned data for errors before trying to use it. What is shown below is just a sample that you could extend to more closely match your requirements. This also considers session time outs and other scenarios...

My initial call:

  $.ajax({ type: 'POST', 
    url: '../doSomething',
    data: 'my data',
    success: function(data) {
      if (HasErrors(data)) return;
      var info = eval('(' + data + ')');
      // do what you want with the info object
    },
    error: function(xmlHttpRequest) {
      ReportFailure(xmlHttpRequest);
    }
  });

And the two helper functions:

function HasErrors(data) {
  if (data.search(/login\.aspx/i) != -1) {
    // timed out and being redirected to login page!
    top.location.href = '../login.aspx';
    return true;
  }
  if (data.search(/Internal Server Error/) != -1) {
    ShowStatusFailed('Server Error.');
    return true;
  }
  if (data.search(/Error.aspx/) != -1) {
    // being redirected to site error reporting page...
    ShowStatusFailed('Server Error. Please try again.');
    return true;
  }
  return false;
}

and

function ReportFailure(msg) {
  var text;
  if (typeof msg == 'string') {
    text = msg;
  }
  else if (typeof msg.statusText == 'string') {
    if (msg.status == 200) {
      text = msg.responseText;
    }
    else {
      text = '(' + msg.status + ') ' + msg.statusText + ': ';
      // use the Title from the error response if possible
      var matches = msg.responseText.match(/\<title\>(.*?)\<\/title\>/i);
      if (matches != null)
      { text = text + matches[1]; }
      else
      { text = text + msg.responseText; }
    }
  }
  // do something in your page to show the "text" error message
  $('#statusDisplay')
    .html('<span class="ui-icon ui-icon-alert"></span>' + text)
    .addClass('StatusError');
}

Following solution is working fine for me :)

$.ajax({
    url: 'http://my_url',
    dataType: "json",
    success: function(data){
      alert('success');
    },
    error: function(data){
      alert('error');
    },complete: function(xhr, data) {
        if(data==="parsererror"){
             alert('404');
        }
    } 
});
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!