跨域?什么是跨域呢?我们先来看看一个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})
监听到了信息就将可以操作返回信息出去了.