Solving Ajax Cross-domain Problem-JSONP Principle Analysis

Posted by shimano55 on Sat, 25 May 2019 01:19:08 +0200

Solving Ajax Cross-domain Problem-JSONP Principle Analysis

Why are there cross-domain problems? - Because there are homologous strategies

  1. Homology is a security policy for browsers. Homology refers to the protocol in the request URL address. Domain names and ports are the same, as long as one of them is different, it is cross-domain.

  2. Homology policy is mainly to ensure the security of browsers.

  3. Under the Same-Origin policy, browsers do not allow Ajax to cross-domain access to server data

    http://www.example.com/detail.html
    //Cross-domain requests:
        http://api.example.com/detail.html domain names are different
        http://www.example.com:8080/detail.html ports are different
        http://api.example.com:8080/detail.html domain name, port different
        https://api.example.com/detail.html protocol and domain name are different
        https://www.example.com:8080/detail.html port, protocol different
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Using jquery ajax-JSONP to call across domains

Although the implementation of jsonp and ajax has no half-money relationship, jsonp is implemented through script src (see the following analysis), but the ultimate goal is to request data from the server and then call back, and for convenience, jquery also encapsulates jsonp in the $. ajax method, the way of invocation is slightly different from the way of ajax invocation, the case is as follows.

  • Test jq_jsonp:

    The target request address, http://www.jepson.com/jq_jsonp.php

        <?php
            $cb</span> = <span class="hljs-variable">$_GET[ 'callback' ];    // Get callback
            $arr = array( 'username' => 'zhangsan', 'password' => '123456' );
            echo $cb</span>.<span class="hljs-string">'('</span>. json_encode(<span class="hljs-variable">$arr) .');'; // Return callback function call
    
            // Namely jQuery1111011117830135968942_1478857963357({"username":"zhangsan","password":"123456"});
        ?>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    In peter.com/jq_jsonp.html, the request is invoked by Jquery ajax method and JSONP method.

        <script type="text/javascript" src="./jquery.js"></script>
        <script type="text/javascript">
            $(function(){
                $("#btn").click(function(){
                    $.ajax({
                        type:'get',
                        url:'http://www.jepson.com/jq_jsonp.php',
                        dataType:'jsonp',
                        jsonp: 'callback', // Callback function, variable name received by background get, callback by default
                        // JsonpCallback:'abc', callback function name, default is a long string, jquery automatically generated, can be seen in the request url
                                                // It doesn't matter whether you change it or not. A shorter one is just a clearer look at the request url.
                        success:function(data){
                            console.log(data.username,data.password);   // zhangsan 123456
                        },
                        error:function(data){
                            console.dir(data);
                            console.log('error');
                        }
                    });
                });
            });
        </script>
        <body>
            <input type="button" value="click" id="btn">
        </body>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    As you can see,'zhangsan 123456'is output.

    Note: If the background does not do the work of getting callbacks and returning function callbacks, then an error will occur and enter the error method. This is a common mistake in our work. Here we should pay attention to it.

Principle Analysis of Solution JSONP

Principle of JSONP: Using the src attribute of script tag to make cross-domain requests, the server response function calls parameters.

Here we understand the principle of JSONP and test it. We need different domains. I am an apache server and I have two virtual hosts.

The domains in which the two domain codes reside http://www.peter.com/ Request domain http://www.jepson.com/

Basic Principle of JSONP - Static Method Creation

Let's take a look at the basic principles of JSONP in solving cross-domain problems through the following static method creation tests
- Test 1:

Target request address, http:/www.jepson.com/1.php
      <?php
          echo "1;";
       ?>
  • 1
  • 2
  • 3
In peter.com/1.html, requests are made through script tags
    <script type="text/javascript" src="http://www.jepson.com/1.php"></script>
  • 1

Open F12, enter the network, find the 1.php request, select Response, and find that the result is 1, cross-domain request is so successful! Yes, the principle is that simple.

But has it been found that we can't get the requested data? What should we do?

The script tag is loaded synchronously by default, so we echo'var a = 1;', and get'var a = 1;', which means that we can think of declaring a variable and assigning it?

And because it's synchronous, can the script statement that follows use this a? Let's have a try.
- Test 2:

Target request address, http:/www.jepson.com/2.php, one line
    <?php
        echo "var a = 1;";
     ?>
  • 1
  • 2
  • 3

In peter.com/2.html, requests are made through script tags

    <!--  Can I understand that a variable is declared here? var a = 1; -->
    <script type="text/javascript" src="http://www.jepson.com/2.php"></script>
    <script type="text/javascript">
        console.log( a );   // 1
    </script>
  • 1
  • 2
  • 3
  • 4
  • 5

F12 opens the console, no mistake! You output a, the output value is 1, and we get the data transmitted in the background.

However, this static approach obviously has many drawbacks. First, it should be placed at the top of the code, otherwise the data returned can not be used below.

Secondly, this static way of parameter configuration is very inconvenient, so we usually create script tags dynamically, add them to the head, and match parameters.

Basic Principle of JSONP-Dynamic Method Creation

The method of creating script tags dynamically, adding them to the header and matching parameters can solve the drawbacks of static creation.
- Test 3:

Target request address, http:/www.jepson.com/3.php, one line
    <?php
        echo "var a = 1;";
     ?>
  • 1
  • 2
  • 3
In peter.com/3.html, script tags are created dynamically through script statements for requests
       <script type="text/javascript">
           var script = document.createElement('script');
           script.src = 'http://www.jepson.com/3.php';
           var head = document.getElementsByTagName('head')[0];
           head.appendChild(script);
           console.log( a );
       </script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Opening F12, something shocking happened, ** The error was reported, ** Uncaught Reference Error: a is not defined (...). ? a variable is undefined?

We open the network, find the 1.php request, click on the response, and find'var a = 1;'. Did the request succeed? What's the situation?

Note: The original way of dynamically creating script to send requests is asynchronous, although the request is successful, but when using variables, the request is not completed, equivalent to not defining variables, and then the error is reported.

What can we do? Here's a little trick, we can echo'foo (123)'; this is equivalent to executing foo (123) after the request, that is, calling the foo function in our code, we write a function foo (data) in the code {console. log (data);} which is equivalent to making callbacks, and we get the data. Here is a code demonstration.

  • Test 4:

    Target request address, http:/www.jepson.com/4.php

        <?php
            echo 'foo(123)';
         ?>
    • 1
    • 2
    • 3

    In peter.com/4.html, script tags are created dynamically through script statements for requests

        <script type="text/javascript">
            var script = document.createElement('script');
            script.src = 'http://www.jepson.com/4.php';
            var head = document.getElementsByTagName('head')[0];
            head.appendChild(script);
    
            function foo(data){
                console.log( data );    //foo(123) calls foo and outputs 123
            }
        </script>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    F12 can see the output 123 and view the request in the network. response can see foo(123)

    Then we can easily get the background data in this dynamic way, but the function names declared by the front end and invoked by the back end need the same, such as the foo above, which is not very good. Every change, it has to dock.

    So we can transfer the callback function name in the parameter. The cases are as follows:

  • Test 5:

    Target request address, http:/www.jepson.com/5.php

        <?php
            $cb</span> = <span class="hljs-variable">$_GET[ 'callback' ];    // get adopt callbackKey to get function name
            $arr = array( 'username' => 'zhangsan', 'password' => '123456' );// We can also pass more complex data.
            echo $cb</span>.<span class="hljs-string">'('</span>. json_encode(<span class="hljs-variable">$arr) .');';// hello( json_encode($arr) )
        ?>
    • 1
    • 2
    • 3
    • 4
    • 5

    In peter.com/5.html, script tags are created dynamically through script statements for requests

        <script type="text/javascript">
            function hello(data){
                console.log(data);// Object {username: "zhangsan", password: "123456"}
                console.log(data.username); // zhangsan
                console.log(data.password); // 123456
            }
            var script = document.createElement('script');
            script.src = 'http://jepson.com/5.php?callback=hello';
            var head = document.getElementsByTagName('head')[0];
            head.appendChild(script);
        </script>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

** Summary: ** The essence of jsonp is to dynamically create script tags, then send cross-domain requests through its src attribute, and then the data format of the server-side response is [function calls]. Therefore, before sending requests, a function must be declared, and the name of the function should be consistent with the name passed in the parameter. The functions declared here are invoked by the content of the server response, which is actually a function call js code. JSONP is a protocol.

Simple encapsulation

Above is the whole principle of JSONP. Below is a simple encapsulation of jquery ajax JSONP implemented in learning. You can refer to it if you are interested.

    function ajax( obj ){
        // The default parameter is passed in the url body due to the jsonp principle.
        // So only get is supported, so type is not configured
        var defaults = {
            url : '#',
            dataType : 'jsonp',
            jsonp : 'callback',
            data : {},
            success : function( data ) { console.log( data ) }
        }

        // When processing parameters, the default parameters are overwritten when transferring functions, and the default parameters are used when not transferring.
        for ( var key in obj ) {
            defaults[ key ] = obj[ key ];
        }

        // Here is the default callback function name, generated from the current date and random number
        var cbName = 'jQuery' + ('1.11.1' + Math.random()).replace(/\D/g,"") + '_' + (new Date().getTime());// Remove all the dots, which is equivalent to adding a string of numbers after jquery plus time numbers
        if( defaults.jsonpCallback ){
            cbName = defaults.jsonpCallback;
        }

        // Here is the callback function, which is called by the server responding to the content.
        // A method is added to the window object, whose name is the value of the variable cbName
        window[ cbName ] = function( data ){
            defaults.success( data );//Here success data is an argument
        }

        // Processing the passed parameter data and adding it to src url
        var param = '';
        for( var attr in defaults.data ){
            param += attr + '=' + defaults.data[ attr ] + '&';
        }
        if( param ){  // Remove the last one&
            param = param.substring( 0, param.length-1 );
            param = '&' + param;
        }

        // Add script tags dynamically and configure parameters
        var script = document.createElement( 'script' );
        // defaults.jsonp background get variable name, cbName callback function name, param variable
        script.src = defaults.url + '?' + defaults.jsonp + '=' + cbName + param; 
        var head = document.getElementsByTagName( 'head' )[ 0 ];
        head.appendChild( script );
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
(function () {('pre.prettyprint code').each(function () { var lines = (this).text().split(′\n′).length;varnumbering = $('
    ').addClass('pre-numbering').hide(); (this).addClass(′has−numbering′).parent().append(numbering); for (i = 1; i

Topics: PHP JQuery Javascript network