To understand JSONP cross – domain principle
preface
I believe many friends know what is cross-domain, for the sake of the unknown friends, here is a brief introduction, cross-domain refers to the browser cannot execute the script of other websites. It is caused by the same origin policy of the browser and is a security restriction imposed by the browser on JavaScript.
Why does JSONP appear
Due to browser security restrictions, data cannot be directly requested across domains (including different root domains, secondary domains, or different ports) unless the target domain authorizes access. So we took a different approach to implementing cross-domain requests. Remember the tags that allow the browser to make cross-domain requests:
iframe
The labelimg
The labellink
The labelscript
The label- . If you don’t know, you need to review it. Next, let’s introduce this and
JSONP
What does it matter?
What is JSONP
JSONP is a dynamic Script tag cross-domain request technique. SRC points to the responder’s server and passes a parameter called callback, which is followed by our functionName. When a request is sent to the responder, Call (undefined,’ the data you want ‘), where ‘the data you want’ is passed in JSON format, hence the name JSONP because of the left and right padding of the JSON data. The backend code constructs and invokes XXX, the browser receives the response, calls xxx.call(undefined,’ data you want ‘), and the requester knows what data he wants.
How to use JSONP
Now let’s do a JSONP cross-domain request “server:” based on Node.
const Koa = require('koa');
const bodyParser = require("koa-bodyparser");
const { getUser } = require("./mock");
const app = new Koa();
app.use(bodyParser());
app.use(async (ctx, next) => {
const { path: curPath } = ctx.request;
if (curPath === '/jsonp') {
// Set the response header
ctx.set('Content-Type'.'application/javascript; charset=utf-8');
ctx.set('X-Content-Type-Options'.'nosniff');
const callback = ctx.query.callback;
let data = getUser(ctx.query.type);
data = JSON.stringify(data);
ctx.body = `${callback}(${data}) `
console.log(ctx.query)
}
});
console.log("Server started!")
app.listen(3030);
Copy the code
“Client:“
const btn: HTMLElement = document.getElementById('btn');
btn.addEventListener('click'.(a)= > {
let url = 'http://127.0.0.1:3030/jsonp? type=all&callback=getdata';
loadScripr(url);
},false)
function loadScripr(src: string) :void {
const script: HTMLScriptElement = document.createElement('script');
script.src = src;
script.onload = (a)= > {
// It is important to delete the script tag every time you create it dynamically, otherwise the entire page will explode
document.body.removeChild(script)
}
script.onerror = (a)= > {
console.error('Request failed');
delete window['getdata'];
document.body.removeChild(script)
}
document.body.appendChild(script);
}
function getdata(data: any) :void {// data indicates the data returned by the server
// to do something
alert(JSON.stringify(data))
}
Copy the code
Ps: The above code does not do compatibility processing, in the use of low-level browsers need to do something about it
When we send the request it will display:Something like this:
<script>
// data is the data returned by the backend
getdata(data)
</script>
Copy the code
So why does this happen? Before we answer that question, let’s take a look backhtml
How do we introduce the outsidejs
Library file, assuming when we introduceJQuery
Library, we can see this field in the response headerContent-Type
:application/javascript;
The part circled in red in the image below, because of this field the browser will parse the response based on the type of the request header, which will execute the code inside, and then our global object will have itJQuery
. As you might have noticed, when we make a request on the server we set the request header to,Content-Type
:application/javascript; charset=utf-8
Therefore, when the browser parses the resource, it will do the corresponding operation according to the response header, which has the following form ~
<script>
// data is the data returned by the backend
getdata(data)
</script>
Copy the code
Since function calls are globally scoped, it is important that our callback functions that receive data be “globally defined on the client side”.
4. Advantages and disadvantages of JSONP
Since JSONP is so useful, what are its advantages and disadvantages? Let’s take a look.
- It is not like
XMLHttpRequest
Object implementedAjax
Requests are restricted by the same origin policy,JSONP
Can cross the same origin policy; - It is more compatible and will run in older browsers without the need
XMLHttpRequest
orActiveX
The support of - After the request is complete, the result can be returned by calling callback. Gives permission to the callback method to the caller. This is going to be the same thing as going to
controller
Layer and theview
The layers finally parted. The JSONP service I provide only provides the data of the pure service, and the page rendering and subsequent view operations after the service are defined by the caller. If you have two pages that need to render the same data, you just need to have different rendering logic, both of which can use the same JSONP service.
“disadvantages“
- It only supports GET requests and does not support other types of HTTP requests such as POST (jSONP is implemented through script SRC, because browsers think they are requesting a resource, so they use GET instead)
- It only supports cross-domain HTTP requests and does not solve the problem of how to make JavaScript calls between two pages in different domains.
- Jsonp does not return various HTTP status codes when a call fails.
- Security. In case the service providing JSONP has a page injection vulnerability, that is, the javascript content it returns is controlled by someone. So what’s the result? Any site that calls this JSONP will have vulnerabilities. So can not control the risk under a domain name… Therefore, when using JSONP, we must ensure that the JSONP service used must be secure and trusted.
- The onerror function of the script tag is only defined in HTML5, and even if we do define the onerror handler, it is not easy to catch the cause of the error