前端程序员必须要知道的跨域问题以及解决方法
node 代理原理同源策略发生在浏览器不发生在服务端,通过一个可以跨域的node
代码,帮前端请求其他后端的数据(即自己写一个后端向其他后端发请求)。图解如下图:
两台机器连接在同一个局域网,自己的前端:
var ajax = new XMLHttpRequest() ajax.open('get', 'http://localhost:3001') ajax.send() ajax.onreadystatechange = () => { if (ajax.readyState == 4 && ajax.status == 200) { console.log(ajax.responseText); } }
自己的后端:
const http = require('http');// const urllib = require('url');http.createServer(function (req, res) { res.writeHead(200, { "Access-Control-Allow-Origin": 'http://127.0.0.1:5500',//只允许自己前端请求 }) http.request({ host: '别人的ip地址', port: '别人后端运行的端口号', method: 'GET', }, result => { result.on('data', function (msg) { console.log(msg.toString()); //拿到数据返回给自己的前端 res.end(msg.toString()) }) }).end() // res.end(JSON.stringify({ msg: 'hello world' }))}).listen(3001, () => { console.log('listening on port 3001');});
Nginx原理它的实现原理和node
代理是一样的,只不过node
代理是通过自己写的后端向别人的后端发请求,而Nginx
是一款软件,使用时只需要配置文件。
Nginx
是开源的轻量级Web
服务器、反向代理服务器,以及负载均衡器和HTTP
缓存器。其特点是高并发,高性能和低内存。它专为性能优化而开发,性能是其最重要的考量,实现上非常注重效率。
Nginx
配置文件由三部分组成:
... //全局块events { //events块 ...}http //http块{ ... //http全局块 server //server块 { ... //server全局块 location [PATTERN] //location块 { ... } location [PATTERN] { ... } } server { ... } ... //http全局块}
第一部分 全局块
主要设置一些影响Nginx
服务器整体运行的配置指令。 比如:worker_processes 1
;worker_processes
值越大,可以支持的并发处理量就越多。
第二部分events
块
events
块涉及的指令主要影响Nginx
服务器与用户的网络连接。 比如:worker_connections 1024
; 支持的最大连接数。
第三部分http
块
http
块又包括http
全局块和server
块,是服务器配置中最频繁的部分,包括配置代理、缓存、日志定义等绝大多数功能。
server
块:配置虚拟主机的相关参数。
location
块:配置请求路由,以及各种页面的处理情况。
创建代理服务器块:在配置文件中,你需要创建一个新的服务器块来定义Node.js
代理。 看下面代码:
server { listen 80; server_name your-domain.com; location / { proxy_pass http://localhost:3000; //将代理请求转发至Node.js应用的地址和端口 proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; }}
在上述示例代码中,your-domain.com
应替换为你的域名或服务器IP
地址。proxy_pass
指令用于将请求转发到Node.js
应用的地址和端口。这里假设Node.js
应用正在本地的 3000 端口上运行,你需要根据实际情况进行修改。
postMessage以上这两种还有上篇文章讲到的两种共四种才是我们最常见的也是应用范围最广的处理跨域的方法,那接下来我们要聊的是不常见的在某些情况下才用得到的方法。
有一个比较老的标签<iframe></iframe>
可以用于页面嵌套子页面,postMessage
方法是window
上的方法,可以用在此;当页面中使用了iframe
嵌套了子页面,父子页面不同源时,postMessage
可以实现通信。
直接看代码:
<!-- 父页面 --><body> <h1>这是首页</h1> <iframe id="another" src="http://127.0.0.1:63251" frameborder="4" width="500" height="400"></iframe> <script> document.getElementById('another').onload = function () { // console.log(this.contentWindow); this.contentWindow.postMessage({ name: 'song', age: 18 }, 'http://127.0.0.1:63251') window.onmessage = function (e) { console.log(e.data); } } </script></body>
<!-- 子页面 --><body> <h3>another page</h3> <script> window.onmessage = function (e) { console.log(e.data, '-----'); e.source.postMessage(`${e.data.name}今年${e.data.age}`, e.origin) } </script></body>
domain这个方法和postMessage
方法一样,也是用在<iframe></iframe>
标签上解决跨域的;只需要声明父子页面的document.domain='xxx'
,来告诉浏览器无需跨域。
代码如下:
<!-- 父页面 --><body> <h1>这是home 页面</h1> <iframe id="about" src="http://127.0.0.1:50250/" frameborder="1"></iframe> <script> document.domain = '127.0.0.1'//告诉浏览器域名一样,只要域名一样就能通信 document.getElementById('about').onload = function () { console.log(this.contentWindow.data);//获取到子页面的数据 } </script></body>
<!-- 子页面 --><body> <h3>about page</h3> <script> document.domain = '127.0.0.1' var data = '这是about页面的数据' </script></body>
WebSocket是什么?WebSocket
是一种在Web
应用程序中实现全双工通信的协议。它允许服务器和客户端之间建立持久的连接,实现实时数据传输和即时通信。Socket
协议不受同源策略的影响,可以跨域。
- 握手(
Handshaking
):在建立WebSocket
连接之前,客户端和服务器之间进行一次初始的HTTP
握手。客户端发送一个包含特定头部信息的HTTP
请求给服务器,服务器验证这个请求,并在响应中返回特定的头部信息,表示握手成功。 - 连接建立:一旦握手成功,
WebSocket
连接就建立起来了,服务器和客户端之间可以进行实时的双向通信。 - 数据传输:在
WebSocket
连接建立后,服务器和客户端可以通过发送消息进行实时的双向通信。服务器和客户端可以随时发送消息给对方,而不需要通过传统的HTTP
请求-响应模式。 - 连接关闭:当通信结束或需要关闭连接时,服务器或客户端可以发送一个特定的关闭帧,表示关闭
WebSocket
连接。
前端:
<body> <script> function myWebScoket(url, params) { return new Promise(function (resolve, reject) { const scoket = new WebSocket(url) // 对这个url建立scoket连接 scoket.onopen = () => { // 向后端发送数据 scoket.send(JSON.stringify(params)) } // 接受响应 scoket.onmessage = (res) => { resolve(res.data) } }) } myWebScoket('ws://localhost:3000', { name: 'song', age: 20 }) .then(data => { console.log(data); }) </script></body>
后端:
const WebSocket = require('ws');const ws = new WebSocket.Server({ port: 3000 })ws.on('connection', (obj) => { // 前端跟我建立了连接 obj.on('message', (msg) => { // 前端给我传递了数据 console.log(msg.toString()); const data = JSON.parse(msg.toString()); let age = data.age setInterval(() => { console.log(age); obj.send(`${data.name} 今年 ${age++} 岁了`); }, 2000)//每隔两秒打印一次 })})
小结对于跨域问题以及解决办法,这两篇文章我们详细地描述了一番,大概就是这7种解决跨域的手段。文章可能有遗漏或错误,欢迎各位大佬指出。