Preface
Hi everyone, this is Lin Sanxin. most difficult knowledge points in the most easy-to-understand is my motto, and based on the premise of advanced is my original intention.
When we do the front-end, it is necessary to connect the interface with the back-end, but many students may have overlooked a problem that may occur during the docking process- cross-domain , then what is cross-domain? Why is it cross-domain? How can it be solved?
Why cross domain?
Why is there a cross-domain problem? Then you have to talk about the browser’s same-origin policy , which stipulates that the protocol number-domain name-port number must be the same as
to comply with the
same-origin policy
If there is a not the same, there will be cross-domain problems. The consequences of
homology policy are:
- 1.
LocalStorge、SessionStorge、Cookie
cannot be accessed across domains - 2.
DOM nodes cannot be operated across domains
- 3.
Ajax request cannot be cross-domain request
Note: One IP can register multiple different domain names, that is, multiple domain names may point to the same IP. Even so, they do not comply with the same-origin policy
The timing of cross-domain?
When did the cross-domain happen? I have tested many classmates and got two answers
- 1. As soon as the request was sent, it was blocked by the browser's cross-domain error report (most people answered)
- 2. The request is sent to the back-end, and the back-end returns data. When the browser receives the back-end data, it is blocked by the browser's cross-domain error report.
Which one is it? We can verify that we first npm i nodemon -g
, then create a index.js
, and then start a node service at nodemon index
// index.js http://127.0.0.1:8000
const http = require('http');
const port = 8000;
http.createServer(function (req, res) {
const { query } = urllib.parse(req.url, true);
console.log(query.name)
console.log('到后端喽')
res.end(JSON.stringify('林三心'));
}).listen(port, function () {
console.log('server is listening on port ' + port);
})
Create another index.html
to write the front-end request code. Let’s write a simple AJAX request.
// index.html http://127.0.0.1:5500/index.html
<script>
//步骤一:创建异步对象
var ajax = new XMLHttpRequest();
//步骤二:设置请求的url参数,参数一是请求的类型,参数二是请求的url,可以带参数
ajax.open('get', 'http://127.0.0.1:8000?name=前端过来的林三心');
//步骤三:发送请求
ajax.send();
//步骤四:注册事件 onreadystatechange 状态改变就会调用
ajax.onreadystatechange = function () {
if (ajax.readyState == 4 && ajax.status == 200) {
//步骤五 如果能够进到这个判断 说明 数据 完美的回来了,并且请求的页面是存在的
console.log(ajax.responseText);//输入相应的内容
}
}
</script>
In the end, the front end did report an error across domains. But this is not the result. If we want to know which answer it is, the key is to see if there is any output from the back-end node service, which is clear at a glance. Therefore, answer 2 is correct.
Same-domain situation && cross-domain situation?
I mentioned the same-origin policy , which satisfies the protocol number-domain name-port number. The three
are the same, which means that
same domain. On the contrary,
cross-domain will cause you to consolidate
look at the same domain and cross domain understanding of 161ac1d2a6a93a!
Solution to cross-domain
Cross-domain is actually a long-standing problem, and there are many corresponding solutions. Let's read on together! ! !
JSONP
As we said earlier, because of the browser same-origin policy , there is the cross-domain problem . Is there anything that is not bound cross-domain problem In fact, yes, the following three tags load resource path is not restricted
- 1. Script tag:
<script src="load resource path"></script>
- 2. Link tag:
<link herf="load resource path"></link>
tag: 161ac1d2a6aa79 <img src="load resource path"></img>
The JSONP is the use of script
of src
load unfettered, so that you can have from the ability to get data of different domains. But JSONP needs front-end and back-end cooperation to achieve the final
cross-domain data acquisition.
In layman's terms, JSONP is: use the src of the script to send the request, pass a method name callback
to the backend, the backend gets the method name, and splices the required data into a new string callback (so Data required) and sent to the front end. After the front end receives this string, it will automatically execute the method
callback (required data). The old rules, first upload the picture, and then the code.
backend code
// index.js http://127.0.0.1:8000
const http = require('http');
const urllib = require('url');
const port = 8000;
http.createServer(function (req, res) {
const { query } = urllib.parse(req.url, true);
if (query && query.callback) {
const { name, age, callback } = query
const person = `${name}今年${age}岁啦!!!`
const str = `${callback}(${JSON.stringify(person)})` // 拼成callback(data)
res.end(str);
} else {
res.end(JSON.stringify('没东西啊你'));
}
}).listen(port, function () {
console.log('server is listening on port ' + port);
})
front-end code
// index.html http://127.0.0.1:5500/index.html
const jsonp = (url, params, cbName) => {
return new Promise((resolve, reject) => {
const script = document.createElement('script')
window[cbName] = (data) => {
resolve(data)
document.body.removeChild(script)
}
params = { ...params, callback: cbName }
const arr = Object.keys(params).map(key => `${key}=${params[key]}`)
script.src = `${url}?${arr.join('&')}`
document.body.appendChild(script)
})
}
jsonp('http://127.0.0.1:8000', { name: '林三心', age: 23 }, 'callback').then(data => {
console.log(data) // 林三心今年23岁啦!!!
})
The disadvantage of JSONP is that it requires front-end and back-end cooperation, and only supports the get request method
WebSocket
What is WebSocket? Actually I don't understand much, but I don't copy the MDN information directly like others, because I believe that everyone can't understand it after copying it.
I understand that WebSocket is a protocol (the same level as http, both protocols), and it can carry out cross-domain communication, why does it support cross-domain communication? I found an article here Why can WebSocket cross domains? , it’s pretty good
backend code
Install npm i ws
// index.js http://127.0.0.1:8000
const Websocket = require('ws');
const port = 8000;
const ws = new Websocket.Server({ port })
ws.on('connection', (obj) => {
obj.on('message', (data) => {
data = JSON.parse(data.toString())
const { name, age } = data
obj.send(`${name}今年${age}岁啦!!!`)
})
})
front-end code
// index.html http://127.0.0.1:5500/index.html
function myWebsocket(url, params) {
return new Promise((resolve, reject) => {
const socket = new WebSocket(url)
socket.onopen = () => {
socket.send(JSON.stringify(params))
}
socket.onmessage = (e) => {
resolve(e.data)
}
})
}
myWebsocket('ws://127.0.0.1:8000', { name: '林三心', age: 23 }).then(data => {
console.log(data) // 林三心今年23岁啦!!!
})
result of 161ac1d2a6ad51 is as follows
Cors
Cors, the full name is Cross-Origin Resource Sharing
, which means cross-domain resource sharing. Cors is generally turned on by the backend. Once turned on, the frontend can access the backend across domains.
Why is Cors enabled on the back end, and the front end can request the back end across domains? My understanding is: the front-end cross-domain access to the back-end, the back-end opens Cors, and sends Access-Control-Allow-Origin: domain name field to the front-end (actually more than one), and the front-end browser judges
Access-Control-Allow-Origin
the same as the front-end domain name. , The browser will not implement cross-domain interception, thus solving the cross-domain problem.
backend code
// index.js http://127.0.0.1:8000
const http = require('http');
const urllib = require('url');
const port = 8000;
http.createServer(function (req, res) {
// 开启Cors
res.writeHead(200, {
//设置允许跨域的域名,也可设置*允许所有域名
'Access-Control-Allow-Origin': 'http://127.0.0.1:5500',
//跨域允许的请求方法,也可设置*允许所有方法
"Access-Control-Allow-Methods": "DELETE,PUT,POST,GET,OPTIONS",
//允许的header类型
'Access-Control-Allow-Headers': 'Content-Type'
})
const { query: { name, age } } = urllib.parse(req.url, true);
res.end(`${name}今年${age}岁啦!!!`);
}).listen(port, function () {
console.log('server is listening on port ' + port);
})
front-end code
// index.html http://127.0.0.1:5500/index.html
//步骤一:创建异步对象
var ajax = new XMLHttpRequest();
//步骤二:设置请求的url参数,参数一是请求的类型,参数二是请求的url,可以带参数
ajax.open('get', 'http://127.0.0.1:8000?name=林三心&age=23');
//步骤三:发送请求
ajax.send();
//步骤四:注册事件 onreadystatechange 状态改变就会调用
ajax.onreadystatechange = function () {
if (ajax.readyState == 4 && ajax.status == 200) {
//步骤五 如果能够进到这个判断 说明 数据 完美的回来了,并且请求的页面是存在的
console.log(ajax.responseText);//输入相应的内容
}
}
results of 161ac1d2a6aecf are as follows
Node interface proxy
Back to same-origin policy , the same-origin policy is only a browser policy, it is not restricted to the backend, that is, front-end-backend will be restricted by the same-origin policy, but
backend-backend It will not be restricted, so you can use the Node interface proxy to first access the backend 1 where Cors has been set up, and then let the backend 1 access the backend 2 to get the data to the backend 1, and the backend 1 transmits the data to the frontend
backend 2 code
// index.js http://127.0.0.1:8000
const http = require('http');
const urllib = require('url');
const port = 8000;
http.createServer(function (req, res) {
console.log(888)
const { query: { name, age } } = urllib.parse(req.url, true);
res.end(`${name}今年${age}岁啦!!!`)
}).listen(port, function () {
console.log('server is listening on port ' + port);
})
Create a index2.js
and nodmeon index2.js
backend 1 code
// index2.js http://127.0.0.1:8888
const http = require('http');
const urllib = require('url');
const querystring = require('querystring');
const port = 8888;
http.createServer(function (req, res) {
// 开启Cors
res.writeHead(200, {
//设置允许跨域的域名,也可设置*允许所有域名
'Access-Control-Allow-Origin': 'http://127.0.0.1:5500',
//跨域允许的请求方法,也可设置*允许所有方法
"Access-Control-Allow-Methods": "DELETE,PUT,POST,GET,OPTIONS",
//允许的header类型
'Access-Control-Allow-Headers': 'Content-Type'
})
const { query } = urllib.parse(req.url, true);
const { methods = 'GET', headers } = req
const proxyReq = http.request({
host: '127.0.0.1',
port: '8000',
path: `/?${querystring.stringify(query)}`,
methods,
headers
}, proxyRes => {
proxyRes.on('data', chunk => {
console.log(chunk.toString())
res.end(chunk.toString())
})
}).end()
}).listen(port, function () {
console.log('server is listening on port ' + port);
})
front-end code
// index.html http://127.0.0.1:5500
//步骤一:创建异步对象
var ajax = new XMLHttpRequest();
//步骤二:设置请求的url参数,参数一是请求的类型,参数二是请求的url,可以带参数,动态的传递参数starName到服务端
ajax.open('get', 'http://127.0.0.1:8888?name=林三心&age=23');
//步骤三:发送请求
ajax.send();
//步骤四:注册事件 onreadystatechange 状态改变就会调用
ajax.onreadystatechange = function () {
if (ajax.readyState == 4 && ajax.status == 200) {
//步骤五 如果能够进到这个判断 说明 数据 完美的回来了,并且请求的页面是存在的
console.log(ajax.responseText);//输入相应的内容
}
}
result of 161ac1d2a6b0ce is as follows
Nginx
In fact, Nginx
Node interface proxy are the same thing, but Nginx does not need us to build an intermediate service.
Download nginx first, and then modify the nginx.conf in the nginx directory as follows:
server{
listen 8888;
server_name 127.0.0.1;
location /{
proxy_pass 127.0.0.1:8000;
}
}
Finally, start nginx through the command line nginx -s reload
backend code
// index.js http://127.0.0.1:8000
const http = require('http');
const urllib = require('url');
const port = 8000;
http.createServer(function (req, res) {
const { query: { name, age } } = urllib.parse(req.url, true);
res.end(`${name}今年${age}岁啦!!!`);
}).listen(port, function () {
console.log('server is listening on port ' + port);
})
front-end code
// index.html http://127.0.0.1:5500
//步骤一:创建异步对象
var ajax = new XMLHttpRequest();
//步骤二:设置请求的url参数,参数一是请求的类型,参数二是请求的url,可以带参数,动态的传递参数starName到服务端
ajax.open('get', 'http://127.0.0.1:8888?name=林三心&age=23');
//步骤三:发送请求
ajax.send();
//步骤四:注册事件 onreadystatechange 状态改变就会调用
ajax.onreadystatechange = function () {
if (ajax.readyState == 4 && ajax.status == 200) {
//步骤五 如果能够进到这个判断 说明 数据 完美的回来了,并且请求的页面是存在的
console.log(ajax.responseText);//输入相应的内容
}
}
results of 161ac1d2a6b288 are as follows
postMessage
Scene: http://127.0.0.1:5500/index.html
page using iframes. Tag embedded in a
http://127.0.0.1:5555/index.html
page
Although these two pages exist in one page, they need iframe tags to be nested. Communication between these two pages is impossible because their
port numbers are different. According to the
same-origin policy, between them There is a
cross-domain problem
What should we do? Use postMessage
to make these two pages communicate
// http:127.0.0.1:5500/index.html
<body>
<iframe src="http://127.0.0.1:5555/index.html" id="frame"></iframe>
</body>
<script>
document.getElementById('frame').onload = function () {
this.contentWindow.postMessage({ name: '林三心', age: 23 }, 'http://127.0.0.1:5555')
window.onmessage = function (e) {
console.log(e.data) // 林三心今年23岁啦!!!
}
}
</script>
// http://127.0.0.1:5555/index.html
<script>
window.onmessage = function (e) {
const { data: { name, age }, origin } = e
e.source.postMessage(`${name}今年${age}岁啦!!!`, origin)
}
</script>
document.domain && iframe
Scenario: Communication between a.sanxin.com/index.html
and b.sanxin.com/index.html
In fact, the above two cannot communicate under normal circumstances, because their domain names are different and belong to cross-domain communication.
then what should we do? In fact, they have one thing in common, that is, their second-level domain names are sanxin.com
, which allows them to communicate document.domain && iframe
Since this rookie does not have a server for the time being, we temporarily use the local to simulate
// http://127.0.0.1:5500/index.html
<body>
<iframe src="http://127.0.0.1:5555/index.html" id="frame"></iframe>
</body>
<script>
document.domain = '127.0.0.1'
document.getElementById('frame').onload = function () {
console.log(this.contentWindow.data) // 林三心今年23岁啦!!!
}
</script>
// http://127.0.0.1:5555/index.html
<script>
// window.name="林三心今年23岁啦!!!"
document.domain = '127.0.0.1'
var data = '林三心今年23岁啦!!!';
</script>
results of 161ac1d2a6b4cf are as follows
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。