跨域问题?同源策略大全

前言:跨域与同源策略

跨域:通常出现在Web开发中,特别是在涉及到Ajax请求或Fetch API调用时,当一个网页尝试从不同的源加载资源时,就会遇到跨域问题。这里所说的"不同的源",是指请求资源的源(由协议、域名和端口号组成)与提供资源的源不一致。

同源策略:是为了保护用户的隐私和数据安全,如果没有同源策略,恶意网站可以通过脚本非法获取其他网站上的敏感数据,所以浏览器会通过实施同源策略来限制不同源之间的直接通信。同时,也有些特别的情况是不受同源策略限制的,比如:

img标签下的

link标签下的

script标签下的

一:JSONP实现同源

  1. 借助script标签的src属性不受同源策略的影响来发送请求

  2. 给后端携带一个参数 callback 并在前端定义 callback 函数体

  3. 后端返回 callback 的调用形式并将要响应的值作为 callback 函数的参数

  4. 当浏览器接收到响应后,就会触发全局的 callback 函数,从而让 callback 以参数的形式接收后端的响应

前端代码

javascript 复制代码
<script>
    function jsonp(url, cb) {
      return new Promise((resolve, reject) => {
        const script = document.createElement('script');

        // 注册一个全局的回调函数
        window[cb] = function(data) {
          resolve(data);
        };

        // 设置脚本标签的src属性为请求的URL,并附加一个回调参数
        script.src = `${url}?cb=${cb}`;

        // 将脚本标签添加到body中,触发异步请求
        document.body.appendChild(script);
      });
    }

    // 使用jsonp函数发起请求
    jsonp('http://localhost:3000', 'callback').then(res => {
      console.log(res);  // 在控制台输出结果
    });
</script>

但使用这种方法实现同源有两个缺点:

  • 需要后端配合
  • 只支持 get 请求

二:cors实现同源

核心思想是后端通过Access-Control-Allow-Origin设置响应头来指定允许的域名,以此来通知浏览器此时同源策略不生效

前端代码

javascript 复制代码
    <script>
        const xhr = new XMLHttpRequest();
        xhr.open('GET', 'http://localhost:3000');
        xhr.send();
        xhr.onreadystatechange = function () {
            if (xhr.readyState == 4 && xhr.status == 200) {
                console.log(xhr.responseText);
        }
    }
    </script>

三:proxy代理

  1. 前端应用将原本需要跨域访问的请求发送给自身的后端服务器
  2. 后端服务器再将请求转发至实际的目标服务器,并从目标服务器获取数据
  3. 最后将数据返回给前端应用。

这样通过后端服务器作为中间层代理转发请求,可以绕过浏览器同源策略的限制,实现跨域数据的获取。

实现过程:

  • 创建一个XMLHttpRequest对象并发送一个GET请求到后端(http://192.168.1.63:3000)。onreadystatechange事件处理器会在请求状态改变时触发,并在请求完成且响应状态码为200 OK时打印出响应文本。
javascript 复制代码
  <script>
        const xhr = new XMLHttpRequest();
        xhr.open('GET', 'http://192.168.1.63:3000');
        xhr.send();
        xhr.onreadystatechange = function () {
            if (xhr.readyState == 4 && xhr.status == 200) {
                console.log(xhr.responseText);
        }
    }
    </script>

四、Websocket实现同源

  • websocket是http协议的一部分,所以它有同源策略
  • websocket是长连接,可以发送和接收消息
  • websocket是html5新增的协议,它是一种双向通信协议,建立在tcp之上

实现过程: 前端

  • 创建一个新的 WebSocket 实例,并传入 url 参数。
  • 设置 onopen 事件处理器,当 WebSocket 连接成功打开时,将 params 对象转换为 JSON 字符串并通过 WebSocket 发送。
  • 设置 onmessage 事件处理器,当从 WebSocket 接收到消息时,解析接收到的数据,并调用 resolve 方法,将解析后的数据作为 Promise 的结果返回。
  • 调用 myWebSocket 函数,传入 WebSocket 服务器的 URL 和一个包含对象并使用 .then 方法处理 Promise 的解决情况
javascript 复制代码
  <script>
    function myWebSocket(url, params = {}) {
      return new Promise(function(resolve, reject) {
        //创建一个新的 `WebSocket` 实例
        const socket = new WebSocket(url)
        
        //将 `params` 对象转换为 JSON 字符串并通过 WebSocket 发送。
        socket.onopen = () => {
          socket.send(JSON.stringify(params))
        }
        
        //解析接收到的数据,并作为 `Promise` 的结果返回
        socket.onmessage = function(e) {
          resolve(e.data);
        }
      })
    }
    myWebSocket('ws://localhost:3000', {age: 18}).then(res => {
      console.log(res);   
    })
  </script>
相关推荐
蒜蓉大猩猩15 分钟前
Vue.js - 组件化编程
开发语言·前端·javascript·vue.js·前端框架·ecmascript
王解1 小时前
一篇文章读懂 Prettier CLI 命令:从基础到进阶 (3)
前端·perttier
乐闻x1 小时前
最佳实践:如何在 Vue.js 项目中使用 Jest 进行单元测试
前端·vue.js·单元测试
檀越剑指大厂1 小时前
【Python系列】异步 Web 服务器
服务器·前端·python
我是Superman丶1 小时前
【前端】js vue 屏蔽BackSpace键删除键导致页面后退的方法
开发语言·前端·javascript
Hello Dam1 小时前
基于 Spring Boot 实现图片的服务器本地存储及前端回显
服务器·前端·spring boot
小仓桑1 小时前
利用 Vue 组合式 API 与 requestAnimationFrame 优化大量元素渲染
前端·javascript·vue.js
Hacker_xingchen1 小时前
Web 学习笔记 - 网络安全
前端·笔记·学习
天海奈奈1 小时前
前端应用界面的展示与优化(记录)
前端
多多*2 小时前
后端并发编程操作简述 Java高并发程序设计 六类并发容器 七种线程池 四种阻塞队列
java·开发语言·前端·数据结构·算法·状态模式