This is the sixth day of my participation in the August More text Challenge. For details, see:August is more challenging

Let’s start with cross-domain error reporting

If I have a test server, the address is 10.128.119.119, port is the default port 80, so a simple interface address can be like this: http://10.128.119.119/api/get/username

Is this interface freely accessible?

The answer is yes. You can access this interface from any network using Postman.

But if you through the browser in the local access, such as calling the interface in the page http://localhost:8000/usercenter.html

$.get('http://10.128.119.119/api/get/username'.function(res){console.log(res)})
Copy the code

Open a look, the error

No ‘Access-Control-Allow-Origin’ header is present on the requested resource.’

This is because browsers have a security policy called the same origin policy.

What is the same origin policy?

Homologous means that the “protocol”, “domain name”, and “port” of the two addresses are the same.

The browser will only allow data communication between two addresses if they are the same origin, which is called the same origin policy.

The Same Origin Policy, originally introduced by Netscape and introduced into browsers, has become the most basic security policy for browsers. It ensures that the application’s resources can only be accessed by the application itself. In this way, users can avoid a lot of malicious attacks from third parties, such as XSS (cross-site scripting attack), CSRF (cross-site request forgery) and so on.

So, when you see the No ‘access-control-allow-Origin’ header above is present on the requested resource. The error message is actually the browser intercepts the data returned from the back end and does not allow the current page to access the data, so on the one hand to avoid local data pollution, on the other hand to avoid user data such as cookie information, account, password and other personal information leakage risk.

Same-origin policy in the development environment

Of course, the same origin strategy is good, but occasionally it can get in our way.

For example, in the software development environment, our local service is usually http://localhost, which must be different from the interface address. In this case, the same origin policy seems to be our obstacle.

There are plenty of solutions online, and many communities have developed their own solutions

For example, we can build a microservice using nodeJS, use http-proxy-middleware to forward Ajax requests for cross-domain purposes, or use WebPack cross-domain proxy configuration.

However, this article is not about the above, but a long time ago jSONP.

The past and present life of JSONP

Before VUE and React, JSONP was a big name. Ajax in jquery adds jSONP requests by default

$.ajax({
    url: "http://10.128.119.119/api/get/username".type: "GET".dataType: "jsonp".jsonpCallback: "callback"            
});

function callback(res){}
Copy the code

You might have noticed earlier that the same origin policy doesn’t seem to work when you use or for file resources such as img and js.

Yes, the SRC attribute of an HTML element is an exception. The SRC attribute is not subject to the same origin policy, which is why JSONP exists. Therefore, JSONP can only support GET requests.

A very simple JSONP request is as follows:

http://digi.duodiangame.com/digMineral/interfaces/task/reportDailySignin.do?callback=cb_callback&user_id=AAA
Copy the code

When you open the url in the browser address bar, you’ll see that the URL returns a function call: cb_callback({“Error”:” user data Error”});

If the current page happens to have a function called ‘cb_callback’, the function is executed, and the arguments are the real return values behind the scenes.

var cb_callback = function(data){
    alert(data.Error)
}

document.write(')
Copy the code

You can copy this code to the console and see what it looks like

So that’s how JSONP gets the data.

To encapsulate the json

Shall we encapsulate a simple JSONP to explain how JSONP should be implemented

function jsonp (url,data,fn){
    if(! url)throw new Error('url is necessary')
    const callback = 'CALLBACK' + Math.random().toString().substr(9.18)
    const JSONP = document.createElement('script')
          JSONP.setAttribute('type'.'text/javascript')

    const headEle = document.getElementsByTagName('head') [0]

    let ret = ' ';
    if(data){
        if(typeof data === 'string')
            ret = '&' + data;
        else if(typeof data === 'object') {
            for(let key in data)
                ret += '&' + key + '=' + encodeURIComponent(data[key]);
        }
        ret += '&_time=' + Date.now();
    }
    JSONP.src = `${url}? callback=${callback}${ret}`;

    window[callback] = function(r){
      fn && fn(r)
      headEle.removeChild(JSONP)
      delete window[callback]
    }

    headEle.appendChild(JSONP)
}
Copy the code

After encapsulation, simply write a background interface. Note here, because jSONp requires the background to return a function call, which is similar to func(response), so we need to dynamically get the function name, and then return the function name call


      
 
$data = "...";
$callback = $_GET['callback'];
echo $callback.'('.json_encode($data).') ';
exit;
 
? >
Copy the code

A simple encapsulation is complete.

How is JSONP used in AXIos

What kind of spark is emitted when JSONP and AXIos collide?

Since AXIos does not support JSONP, we need to add jSONP methods to Axios, and we can use promises instead of callback parameters

axios.jsonp = (url,data) = >{
    if(! url)throw new Error('url is necessary')
    const callback = 'CALLBACK' + Math.random().toString().substr(9.18)
    const JSONP = document.createElement('script')
          JSONP.setAttribute('type'.'text/javascript')

    const headEle = document.getElementsByTagName('head') [0]

    let ret = ' ';
    if(data){
        if(typeof data === 'string')
            ret = '&' + data;
        else if(typeof data === 'object') {
            for(let key in data)
                ret += '&' + key + '=' + encodeURIComponent(data[key]);
        }
        ret += '&_time=' + Date.now();
    }
    JSONP.src = `${url}? callback=${callback}${ret}`;
    return new Promise( (resolve,reject) = > {
        window[callback] = r= > {
          resolve(r)
          headEle.removeChild(JSONP)
          delete window[callback]
        }
        headEle.appendChild(JSONP)
    })
    
}
Copy the code

The invocation has also changed:

axios.jsonp(url, params)  
     .then(res= > console.log(res))        
     .catch(err= > console.log(err))
Copy the code

This is the end of the text, if you have any mistakes, please leave a comment in the comments section