In modern programming, the front and back ends are already deployed separately, with the front end having its own domain and the back end having its own domain. Due to the restriction of the browser’s same-origin policy, non-same-origin requests can cause cross-domain problems. There are many ways to solve cross-domain problems, such as CORS(Cross Orign Resources Share) and JSONP. Here I will focus on the JSONP solution.
1. Basic concepts
-
Same-origin policy: Same protocol, same domain name, and same end number. Anything less than one of the three is a cross-domain problem. Here are a few simple examples: 1: the request from https://www.a.com:8080 to http://www.a.com:8080 will be cross-domain (the domain name and port are the same but the protocol is different) 2: Requests from https://www.a.com:8080 to https://www.b.com:8080 will be cross-domain (same protocol and port but different domain name) 3: Requests from https://www.a.com:8080 to https://www.a.com:9090 are cross-domain (same protocol, same domain name but different port)
-
Cross-domain: Cross-domain security restrictions are imposed on the browser side, but not on the server side. The browser’s same-origin policy restricts documents or scripts loaded from one source from interacting with resources from another.
Two: difference between JSON and JSONP
- JSON, which stands for JavaScript Object Notation, is a lightweight data interaction format. It is based on a subset of ECMAScript (the JS specification of the European Computer Association) and uses a text format that is completely independent of the programming language to store and represent data. In a nutshell, JSON is a data format for transferring data.
- JSONP is an informal transport protocol that allows the user to pass a callback(or start by defining a callback method) argument to the server, which then returns the data wrapped around the JSON data as a function name. The client can then customize its own functions to automatically process the returned data.
Three: Jump out of the same “comfort zone”
We found that calling js files on web pages is not affected by cross-domain issues. We also found that tags with SRC attributes have cross-domain capabilities, such as IMG and script. In HTML pages we often import images, using the SRC attribute in the IMG tag to request a static resource.
<script src="http://localhost:9090/api"></script>
Copy the code
Four: principle and cross-domain implementation
- The jSONP execution process is actually a simple two-step process. First, a callback function with parameters is pre-defined on the front end to accept data from the back end. Second, a server service is started on the back end, and the data to be passed is passed to the front end in the form of a defined callback function name plus the return result.
// 1 callback // 2 back-end callbackName(data)functiononResponse(posts) { console.log(posts); } // The front end does not call </script> <! -- back end returns result --> <! Call --> <script SRC ="http://localhost:9090/api"></script>
Copy the code
// const HTTP = require('http');
http.createServer((req, res) => {
if (req.url === '/api') {
let posts = ['js'.'php'];
res.end(`onResponse(${JSON.stringify(posts)}) `); } }) .listen(9090, () => { console.log(9090) })Copy the code
- Encapsulating the above is a simple request, there will be many requests in the actual project, we certainly can’t define a row of script tags and callback functions. The resulting code is too inflexible. One of the goals of encapsulation is to give the front end the flexibility to change the names of predefined callback functions, rather than locking callback functions to the front and back ends. Also, by wrapping the code, we don’t have to create the callback function manually. The wrapped function will automatically place the SRC address and create the callback name.
// backend const HTTP = require('http');
const url = require('url'); http.createServer((req, res) => { // /api? Callback =onResponse // Parse the callback name in the front-end request URLif(req.url.includes('/api')) {
let myurl = url.parse(req.url);
let params = new URLSearchParams(myurl.query)
let posts = ['js'.'php'];
let mathodName = params.get('callback');
res.end(`${mathodName}(${JSON.stringify(posts)})`)
}
})
.listen(9090, () => {
console.log(9090);
})
Copy the code
// The front end (the code is executed in the body)functionJsonp (url, options) {// Timeout handling const {timeout} = options;returnNew Promise((resolve, reject) => {// Prevent function name conflictslet funcName = `jsonp${Date.now()}`;
lettime = null, scriptNode; // Define callback window[funcName] =function(data) {
if(timeout) clearTimeout(time); resolve(data); // Clear the callback function generated by this request and the script tag delete window[funcName]; document.body.removeChild(scriptNode); } // create script tag scriptNode = document.createElement('script'); // Add SRC attribute scriptNode. SRC = 'to script tag${url}? callback=${funcName}`; / / request document. The body. The appendChild (scriptNode); time =setTimeout(() => {
reject('network err, timeout')}, timeout) // fail scriptNode.onerror =function(err) {
reject(err);
}
})
}
jsonp('http://localhost:9090/api', {
callBack: 'res1'Then (res => {console.log())'jsonp->', res); }) // Request failed. Catch (err => {console.log("network err!")
})
</script>
Copy the code
Five:
Advantage 1:
- It is not restricted by the same origin policy as Ajax requests implemented by the XMLHttpRequest object
- It is more compatible, runs in older browsers and does not require XMLHttpRequest or ActiveX support
- After the request is complete, the result can be returned by calling callback
2: the drawback
- It only supports GET requests and does not support other types of HTTP requests such as POST
- 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