Solve the error generated when jQuery uses JSONP _ jquery

Source: Internet
Author: User
This article describes how to solve the errors caused by jQuery's use of JSONP. For more information, see What is a domain?In short Protocol + domain name or address + Port, 3, as long as there is any difference, it means not in the same domain. Cross-Domain: access data from another domain in one domain.

If you only load the content of another domain and do not need to access the data in it, cross-domain is very simple, such as usingIframe. However, if you need to load and use the data from another domain, it will be troublesome. To ensure security, the browser imposes strict restrictions on this situation. You must make some settings on both the client and server to implement cross-origin requests.

Introduction to JSONP
JSONP(JSON with Padding) is a common cross-origin method, but only supports JS scripts and JSON format data. As the name suggests,JSONPJSON is a technical method to implement cross-origin requests. The basic principle is to use HTMLScriptA tag is inherently cross-origin. When JSON data of another domain is loaded, a callback function is automatically run to notify the caller. This process requires support from the server of another domain, so the cross-domain implementation in this way is not arbitrary.

JQuery's support for JSONP
JQuery's Ajax object supports cross-origin requests in the JSONP mode by specifying the crossDomain parameter to true and the ype parameter to jsonp [1], or using the abbreviated form: getJSON () method [2]. For example:

// Set crossDomain and dataType parameters to use JSONP $. ajax ({dataType: "jsonp", url: "http://www.example.com/xxx", crossDomain: true, data :{}}). done (function () {// processing function upon request Completion}); // use getJSON $. getJSON ("http://www.example.com/xxx? Jsoncallback =? ", {// Parameter}, function () {// processing function upon request Completion });

UseGetJSONYou must specify jsoncallback =? In the parameter ?, This is the callback function mentioned above. JQuery will automatically replace the question mark in this parameter with a randomly generated value (callback function name) to formJsoncallback = jQueryxxxxxxxParameters in this form, and then use the GET method with other parameters to send requests.

When using the first method, you only needDataTypeIf the parameter value is set to jsonp, JQuery automatically adds the jsoncallback parameter to the request address. Therefore, you do not need to manually add the parameter.

JQuery cross-origin request defects: Error Handling
Cross-origin requests may fail. For example, the security settings of the other server refuse to accept requests from US (we are not in the Trust List of the other server), or the network is disconnected, or the other server is disabled, or the request address or parameter is incorrect, causing the server to report an error.

In JQuery, when a request is sent using ajax or getJSON, A jqXHR object [3] is returned. This object implements the Promise protocol, so we can use its done, fail, always and Other interfaces to process callback. For example, we can use its fail callback to handle errors when a request fails:

var xhr = $.getJSON(...);xhr.fail(function(jqXHR, textStatus, ex) {  alert('request failed, cause: ' + ex.message);});

This method can handle "normal errors", such as timeout, request suspension, and JSON parsing errors. However, it does not provide good support for "abnormal errors", such as network failures and server shutdown.

For example, if the target server cannot be accessed normally, you will see an error message on the console in Chrome:

JQuery does not handle this error, but selects "quiet failure ":FailThe callback will not be executed, and your code will not receive any feedback. Therefore, you have no chance to handle such errors and cannot report errors to users.

One exception is in IE8. In IE8, when the network cannot be accessed, ScriptIf the tag is the same, the loaded information is returned. Therefore, JQuery cannot determine whether the tag is successfully loaded Based on the script tag status, however, it finds that the callback function is not executed after the script label is "loaded successfully", so JQuery determines that this is a "Resolution error" (the callback code is not executed, probably because the returned data is incorrect and the execution fails), the returned error message is "xxxx was not called", where xxxx is the name of the callback function.

That is to say, due to this wonderful feature of IE8 (similar to IE7), JQuery cannot choose the "silent failure" policy in the case of "abnormal errors" such as network failure, so we can benefit from this and get the opportunity to handle errors. For example, in this case, the "xxxx was not called" dialog box is displayed.

Solution
In case of an "abnormal error", all JSONP of JQuery except IE7 and 8 will be "silent" in newer browsers ". However, we often want to capture and handle such errors.

In fact, in these browsers, the script tag triggers an error when encountering these errors. For example, we can implement JSONP by ourselves:

var ele = document.createElement('script');ele.type = "text/javascript";ele.src = '...';ele.onerror = function() {  alert('error');};ele.onload = function() {  alert('load');};document.body.appendChild(ele);

In the new browser, an error event is triggered when an error occurs, and an onerror callback is executed to bring up the alert dialog box:

But the trouble is that JQuery won't take thisScriptLabels are exposed to us, so we have no chance to add them.Onerror eventProcessor.

The following is JQuery implementationJSONPMain Code:

jQuery.ajaxTransport( "script", function(s) { if ( s.crossDomain ) {  var script,   head = document.head || jQuery("head")[0] || document.documentElement;  return {   send: function( _, callback ) {    script = document.createElement("script");    script.async = true;    ...    script.src = s.url;    script.onload = script.onreadystatechange = ...;    head.insertBefore( script, head.firstChild );   },   abort: function() {    ...   }  }; }});

The script is a local variable and cannot be obtained from the outside.

Is there a solution? Of course:

  • Implement JSONP by yourself without using
  • Modify JQuery source code (provided that you do not reference JQuery using CDN)
  • Tips

The first two types are not mentioned. If you are willing to do so, you can choose. The following describes another technique.

Through the source code above, we can find that although JQuery does not expose the script variable, it "exposes" the location of the script tag. The last sentence of the send method:

Head. insertBefore (script, head. firstChild );
You can know that the newly created label is added as the first element of the head. And we do the opposite, as long as we can get thisHeadElement. Can this script be obtained? What is head? Continue to read the source code and see how the head came from:

Head = document. head | jQuery ("head") [0] | document.doc umentElement;
We can get it in the same way, so we can complete the previous example as follows:

var xhr = $.getJSON(...);// for "normal error" and ie 7, 8xhr.fail(function(jqXHR, textStatus, ex) {  alert('request failed, cause: ' + ex.message);});// for 'abnormal error' in other browsersvar head = document.head || $('head')[0] || document.documentElement; // code from jqueryvar script = $(head).find('script')[0];script.onerror(function(evt) {  alert('error');});

In this way, we can capture "abnormal errors" in all browsers (strictly speaking, because I didn't test all browsers.

In other browsers except IE7 and 8, when the network is disconnected, JQuery fails silently, it also leaves a pile of garbage and does not clean up, that is, the newly created script tag and global callback function. Although staying there is no major harm, isn't it better if you can easily clear it? So we can implement onerror as follows:

// handle erroralert('error');// do some clean// delete script nodeif (script.parentNode) {  script.parentNode.removeChild(script);}// delete jsonCallback global functionvar src = script.src || '';var idx = src.indexOf('jsoncallback=');if (idx != -1) {  var idx2 = src.indexOf('&');  if (idx2 == -1) {  idx2 = src.length;  }  var jsonCallback = src.substring(idx + 13, idx2);  delete window[jsonCallback];}

In this way, it will become perfect.

Complete code

function jsonp(url, data, callback) {  var xhr = $.getJSON(url + '?jsoncallback=?', data, callback);  // request failed  xhr.fail(function(jqXHR, textStatus, ex) {    /*     * in ie 8, if service is down (or network occurs an error), the arguments will be:     *      * testStatus: 'parsererror'     * ex.description: 'xxxx was not called' (xxxx is the name of jsoncallback function)     * ex.message: (same as ex.description)     * ex.name: 'Error'     */    alert('failed');  });  // ie 8+, chrome and some other browsers  var head = document.head || $('head')[0] || document.documentElement; // code from jquery  var script = $(head).find('script')[0];  script.onerror = function(evt) {    alert('error');    // do some clean    // delete script node    if (script.parentNode) {      script.parentNode.removeChild(script);    }    // delete jsonCallback global function    var src = script.src || '';    var idx = src.indexOf('jsoncallback=');    if (idx != -1) {      var idx2 = src.indexOf('&');      if (idx2 == -1) {        idx2 = src.length;      }      var jsonCallback = src.substring(idx + 13, idx2);      delete window[jsonCallback];    }  };}

The above code has been tested and passed in IE8, IE11, Chrome, FireFox, Opera, and 360. Among them, 360 is the IE kernel version, and other browsers are not tested yet.

I hope this article will help you solve the errors caused by jQuery's use of JSONP.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.