跨域?什么是跨域呢?我们先来看看一个url的组成,http://192.x.x:3000/home,这一个url我们可以分成四部分来看http是协议,192.x.x是域名,3000是端口,home是路径.在浏览器中,我们从一个域名发送请求到另一个域名,如果两个域名的协议,域名,端口三部分只要存在一部分不同就会发生跨域,也就是说只有两个域名的协议,域名,端口都相同才会不会发生跨域,所以我们又如何解决跨域的问题呢?在下文中会给大家介绍几种方法去解决跨域问题.

那么要解决跨域就不得不谈及同源策略,同源策略是一种安全措施,用于防止恶意网站通过脚本获取或修改其他网站的数据.只要协议,域名,端口,三者其中一个不一致,在请求响应过程中就会触发同源策略.

JSONP

第一种方式是JSONP,但是跟JSON并没有关系,这只是一种称呼.那么JSONP的实现原理也是非常简单的,我们来想想,平时我们在页面加载图片时<img src="" alt="">是不是可以正常加载页面,我们的scr里面是放的地址,这里是需要发送请求的,如果按照跨域的说法,这里势必会发生跨域,但是事实上这里并没有发生跨域,图片依旧可以正常加载.原因是如果加载图片一直需要解决跨域的话,就会很麻烦,索性就把src放进了“白名单”不会发生跨域,类似的<link rel="stylesheet" href="">,<script src=""></script>都不会发生跨域,因此JSONP的过程就采取了这个方式.

我们在JS中创建一个script的标签,并设置src属性并插入到html中就可以了.但是这样我们就无法操作接口请求发送响应获取到的数据了,这里我们就需要打造一下.

 1<!DOCTYPE html>
 2<html lang="en">
 3<head>
 4    <meta charset="UTF-8">
 5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 6    <title>Document</title>
 7</head>
 8<body>
 9     <script>
10        function jsonp(url,cb){
11            return new Promise((resolve,reject)=>{
12                const script = document.createElement('script')
13
14                window[cb] = function(data){
15                    resolve(data)
16                }
17
18                script.src = `${url}?cb=${cb}`
19                document.body.appendChild(script) 
20            })
21        }
22        jsonp('http://localhost:3000','callback').then(res=>{
23            console.log(res);
24        })
25     </script>
26</body>
27</html>

window[cb]是我们在全局声明了一个叫cb的函数.拿到响应返回的数据我们借助了new Promise来处理异步请求,并使用resolve()传递数据.在后端操作可能就比较绕了.

 1const http = require('http');
 2
 3http.createServer(function (req, res){
 4    const query = new URL(req.url,`http://${req.headers.host}`).searchParams
 5    console.log(query);
 6    if(query.get('cb')){
 7        const cb = query.get('cb')
 8        const data = 'hello world'
 9        const result = `${cb}("${data}")`
10        res.end(result)
11    }
12}).listen(3000)

new URL(req.url,`http://${req.headers.host}`).searchParams是获取到请求携带的参数,这里返回的是一个map对象,所以取值我们用的是get(key).
const cb = query.get('cb') :获取到携带的参数callback 这里 cb = callback
const data = 'hello world':实参,传给函数
const result = `${cb}("${data}"):这里就会比较绕了,首先cb是指callback,这里加上()就变成一个函数的样子callback(),data实参,就变成了callback("hello world")再使用res.end(),这里浏览器就是把这个函数给执行了.也就是把这一串执行了

 1window[cb] = function(data){
 2                    resolve(data)
 3            }

总的来说JSONP的操作原理就是借助script的标签的src属性不受同源策略的影响,来发送请求,给后端携带一个参数callback 并在前端定义callback函数体,后端返回callback 的调用形式并将要影响的值作为callback,当浏览器接受到响应后,就会触发全局的callback函数,从而让callback以参数的形式接收到后端的响应.

cors

使用cors处理同源,这个用一句话说明就是通过在后端代码中,操作http响应头添加‘Access-Control-Allow-Origin’字段,来限制任意url不会被同源策略操作,从而达到解决跨域. 前端代码:

 1<!DOCTYPE html>
 2<html lang="en">
 3<head>
 4    <meta charset="UTF-8">
 5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 6    <title>Document</title>
 7</head>
 8<body>
 9    <script>
10        const xhr = new XMLHttpRequest();
11        xhr.open('GET', 'http://localhost:3000', true); 
12        xhr.send();
13        xhr.onreadystatechange = function() {
14            if(xhr.readyState === 4 && xhr.status === 200){
15                console.log(xhr.responseText);
16            }
17        }
18    </script>
19</body>
20</html>

后端代码:

 1const http = require('http');
 2
 3http.createServer(function (req, res){
 4    res.writeHead(200, {
 5        'Access-Control-Allow-Origin': '*',
 6        
 7    });
 8    res.end('hello world')
 9}).listen(3000)

我们操作这一个字段Access-Control-Allow-Origin,设置哪一个源可以跨域,这里*是指所有的源都可以.

nginx

其实nginx的原理就是代理,当发送请求过程中会被nginx代码后再到接受请求,然后在响应的过程中,也会在nginx中被代理后再返回出去.这个nginx主要用于项目部署到服务器上时使用的.

WebSocket

scoket协议天生不受同源策略的影响这一点就非常的厉害,那么它的作用是什么呢?它是双端管道,信息是双向传递的,不用只有一发送了请求,才会响应信息给你.

我们可以这张极其简陋的图,这里A随时发消息给B,B不做请求也可以也接收到,A不作出请求,B也可以随时发消息给A.

我们先在终端使用npm init -y初始化一下一个后端项目,并npm i ws

这里我们使用的WebScoket协议而不是HTTP协议

 1<!DOCTYPE html>
 2<html lang="en">
 3<head>
 4    <meta charset="UTF-8">
 5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 6    <title>Document</title>
 7    
 8</head>
 9<body>
10    <script>
11        function myWebSocket(url,params={}) {
12            return new Promise((resolve,reject)=>{
13                const socket = new WebSocket()
14                socket.onopen = ()=>{
15                    socket.send(JSON.stringify(params))
16                }
17                socket.onmessage = (e)=>{
18                    resolve(e.data)
19                }
20            })
21        }
22        myWebSocket('ws://localhost:3000',{age:18}).then(res=>{
23            console.log(res);
24        })
25    </script>
26</body>
27</html>

这里需要注意的是WebScoket只能接受字符串数据,所以这里socket.send(JSON.stringify(params))我们要处理一下处理的类型.

后端我们需要监听连接事件。当连接后我们就要监听信息

 1const webSocket = require('ws')
 2
 3const ws = new webSocket.Server({port:3000})
 4ws.on('connection',function(obj){
 5    obj.on('message',function(data){
 6        obj.send('hello world')
 7    })
 8})

监听到了信息就将可以操作返回信息出去了.

个人笔记记录 2021 ~ 2025