浅谈前端跨域及解决方法

199 阅读4分钟

一、同源策略

同源策略是浏览器的一个安全策略机制。
源 = 协议 + 主机/域名 + 端口号,当中URL的协议、域名、端口号都一样叫同源,两个源不同称为跨源、跨域。

同源策略是指:页面的源和页面运行时加载的源不同时,出于安全考虑,浏览器会对跨域的资源访问进行一些限制。(同源策略旨在防止恶意网站利用跨域请求获取用户的敏感信息或执行恶意操作。)

这里需要明确的是,跨域是发生在浏览器端的,在后端是不存在跨域问题。

举个栗子---页面源是http://localhost:8080,加载源是http://www.juejin.com。(不写端口号默认的是80) 域名不同:localhost和www.juejin.com不同。 端口不同:8080和80。

but,请求没有发出去吗?让我们分析分析这个过程!

  1. 浏览器请求发出去了
  2. 服务器也接收到请求了
  3. 服务器也能处理请求
  4. 服务器也能给出响应结果
  5. 浏览器也能接收到响应结果此时 我们的代码还在等着请求结果
  6. 浏览器拿到结果后要把结果递交给代码,此时监测到当前页中的 URL 与请求的 URL 不同源,所以浏览器判定跨域了,报了一个跨域错误
  7. 代码没有接收到结果,得到一个错误

也就是说,跨域发生在浏览器递交结果给代码的前一刻,浏览器发现协议或域名或端口不同进而判定跨域,使得代码没有获得到响应结果而是报了一个跨域的错误。

二、跨域解决方法

1、JSONP(JavaScript json and padding)---前端+后端

  • 通过利用动态创建script标签的src属性来实现访问数据的,因为src是不存在跨域的。
  • 前端需要做的就是传一个函数的参数,接收返回的数据就是在函数里面接收
  • 后端需要做的就是接收传过来的参数,然后返回函数的调用里面传需要返回的数据,注意返回的数据必须是字符串形式的

例:

<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    function fn(e){
      console.log(JSON.parse(e),'接收到的数据!');
    }
  </script>
  <script src="http://127.0.0.1:8080/list?fn=fn"></script>
</body>
</html>
---------------------------------------------------------------------------------
const  express=require('express')
const  app=express()
const arr = [{
  id:0,name:'张三
}]
app.get('/list',(req,res)=>{
  console.log(req);
  const fn = req.query.fn
  res.send(fn+`(${JSON.stringify(arr)})`)  //arr必须是字符串
})
app.listen(8080,'127.0.0.1:8080',()=>{
  console.log('http://127.0.0.1:8080:8080');
})

注意:jsonp只能发送get请求,发送的不是ajax请求,是单独的请求方式

2、proxy(代理)---前端

例:

module.exports = defineConfig({
  transpileDependencies: true,
  lintOnSave: false,
  //开启代理服务器(方式一)
  // devServer: {
  //   proxy: 'http://localhost:5000'
  // }

  // 开启代理服务器(方式二)
  devServer: {
    proxy: {
      '/api': {
        target: 'http://localhost:5000',
        // 匹配所有以api开头的转换为空字符串
        pathRewrite: { '^/api': '' },
        // 用于支持websocket
        ws: true,
        // 不写的话,默认为true,用于控制请求头中的host值(请求来自于哪里)
        changeOrigin: true
      },
      //匹配所有以proxyApi开头的转换为空字符串
      '/proxyApi': {
        target: 'http://localhost:5001',
        pathRewrite: { '^/proxyApi': '' },
      }
    }
  }
})

3、cors---后端

4、WebSocket

websocket是HTML5开始提供的一种网络通信协议,它的目的是在浏览器之间建立一个不受限的双方通信的通道,比如说,服务器可以在任意时刻发送信息给浏览器。在websocket的API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

WebSocket 的方法

  • ws.send() - 向服务器发送数据
  • ws.close() - 关闭连接

WebSocket 的事件

  • ws.onopen - 建立连接时触发
  • ws.onmessage - 客户端接受服务端数据时触发
  • ws.onerror - 通信错误时触发
  • ws.onclose - 连接关闭时触发

WebSocket.readyState

  • readyState 属性返回实例对象的当前状态,共有四种状态
  • 0 - 表示正在连接
  • 1 - 表示连接成功,可以进行通信
  • 2 - 表示连接正在关闭
  • 3 - 表示连接已经关闭,或者打开连接失败

栗子:

var ws = new WebSocket("接口地址")
// 连接成功时触发
ws.onopen = function() {
    console.log("连接成功")
}
// 连接失败时触发
ws.onerror = function() {
    console.log("连接失败")
}
// 发送数据
ws.send(); // 向服务端发送请求

// 接收消息时触发
ws.onmessage = function(MessagEvent) {
    console.log(MessagEvent.data)
}
// 连接关闭的回调函数
ws.onclose = function(){
	console.log("close")
}