小白也能看懂的解决跨域的三种方式

前言:

由于浏览器为了防止恶意网站窃取用户在其他网站的敏感信息,如用户登录状态、个人数据等。于是浏览器就会开启同源策略。 同源策略:它限制一个源的文档或者加载的 JS 脚本,与另外一个源的资源进行交互,帮助我们阻隔恶意文档,减少被攻击的媒介

同源策略

  • 一个 "源" 是由协议(scheme)、主机(host)和端口(port)来定义的。只有当这三个部分完全相同的时候,两个网页才被认为是同源的。
  • 是浏览器的一种安全机制,它规定了只有来自相同 "源" 的脚本才能访问当前网页的文档对象模型(DOM)、本地存储(localStorage 等)、会话存储(sessionStorage)、Cookies 以及其他敏感资源。

解决跨域

跨域的本质就是使得浏览器不触发同源策略

JSONP

使用JSONP方式实质上是借用了浏览器的一种取巧方式实现,它可能看起来不怎么优雅。由于浏览器在对包括imgscriptradio等html标签发送的网络请求并不会触发浏览器使用同源策略的,于是我们便可以利用这个漏洞实现跨域问题。

首先我们创建一个server.js,使用node在3000端口处打开服务器

js 复制代码
const http = require('http')

http.createServer((req, res) => {
  res.end('success')
})
  .listen(3000)

其次创建index.html,将监听的地址放入script的src中

js 复制代码
 function JSON(url) {
      return new Promise((resolve, reject) => {
        const script = document.createElement('script')
        script.src = url
        document.body.appendChild(script)
      })
    }


    JSON('http://localhost:3000')
      .then(res => {
        console.log(res);
      })

我们封装了一个JSONP函数,为了拿到结果的异步操作,使得该函数返回一个Promise对象。但很快我们就会发现一个问题,我们根本没有拿到返回的数据显示的是该数据success没有被定义,并且正常的GET请求是能够传递params参数。

转换一个思路,如果我们通过window全局去触发这个函数呢?在加载全局的时候直接将该方法挂载上去,在服务器响应回来拿到数据的时候,直接将挂载在window上的方法触发,并且通过url传递我们需要的params参数。

js 复制代码
    function JSON(url, callback) {
      return new Promise((resolve, reject) => {
        const script = document.createElement('script')
        window[callback] = function (data) {
          resolve(data)
        }
        script.src = `${url}?callback=${callback}`
        document.body.appendChild(script)
      })
    }


    JSON('http://localhost:3000', 'callback')
      .then(res => {
        console.log(res);
      })

同时后端那边也需要协助我们完成这一次操作,后端需要再拿到url的请求后,处理分离出函数名,并将后端的实参传递到挂载在window的函数上面。

js 复制代码
const http = require('http')

http.createServer((req, res) => {
  const query = new URL(req.url, `http://${req.headers.host}`).searchParams
  if (query.get('callback')) {
    const callback = query.get('callback')
    const data = '我是数据'
    const result = `${callback}("${data}")`
    res.end(result)
  }
  res.end('success')
})
  .listen(3000)

值得一提的是JSONP方式只能过去处理GET请求,这是由于script标签本身只能发送GET请求,从而限制了JSONP方式只能处理该请求

WebSocket

使用WebSocket协议,WebSocket 连接建立时会使用 HTTP 协议进行握手。客户端发起一个特殊的 HTTP 请求,这个请求中包含一些特殊的头部信息,用于表明这是一个 WebSocket 升级请求。

WebSocket 是全双工协议,一旦连接建立,服务器和客户端可以在这个连接上双向自由地发送数据,不需要像 HTTP 那样每次重新建立连接来进行通信。

首先建立后端的服务器

js 复制代码
const WebSocket = require('ws')
const ws = new WebSocket.Server({ port: 3000 })
ws.on('connection', (obj) => {
  obj.on('message', (data) => {
    obj.send('我是 WebSocket')
  })
})

建立连接请求

js 复制代码
function web_Socket(url) {
      return new Promise((resolve) => {
        const socket = new WebSocket(url)
        socket.onopen = () => {
          socket.send('http://localhost:3000')
        }
        socket.onmessage = (res) => {
          resolve(res.data)
        }
      })
    }

    web_Socket('http://localhost:3000').then(data => {
      console.log(data);
    })

CORS

采用 CORS (跨域资源共享),一种基于 HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其他源(域、协议或端口),来访问加载服务器上的资源。

其实际上就是通过添加在响应头中的特殊字段,使得浏览器不会使用同源策略对响应资源进行干扰。

后端建立服务器同时设置允许的源,当然我们也能设置成'Access-Control-Allow-Origin': '*' 这样会允许所有的源对服务器进行访问,我们可以设置自己响应的源进行访问。

js 复制代码
const http = require('http');

http.createServer(function (req, res) {
  res.writeHead(200, {
    'Access-Control-Allow-Origin': 'http://127.0.0.1:5500'
  })
  res.end('hello world')
}).listen(3000);

前端通过ajax发送请求

js 复制代码
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);

      }
    }

总结

总而言之,所有的跨域解决方式都是需要通过后端进行特殊的处理操作,或者是前后端一起对接工作进行特殊的处理。当然解决跨域的方式远不止这些,还有诸如postMessage、nginx等方式能解决跨域问题,大家可以自行进行学习拓展哦!

相关推荐
还有几根头发呀1 小时前
UDP 与 TCP 调用接口的差异:面试高频问题解析与实战总结
网络·网络协议·tcp/ip·面试·udp
Dontla3 小时前
为什么React列表项需要key?(React key)(稳定的唯一标识key有助于React虚拟DOM优化重绘大型列表)
javascript·react.js·ecmascript
EndingCoder4 小时前
React从基础入门到高级实战:React 实战项目 - 项目三:实时聊天应用
前端·react.js·架构·前端框架
阿阳微客5 小时前
Steam 搬砖项目深度拆解:从抵触到真香的转型之路
前端·笔记·学习·游戏
德育处主任Pro6 小时前
『React』Fragment的用法及简写形式
前端·javascript·react.js
CodeBlossom6 小时前
javaweb -html -CSS
前端·javascript·html
CodeCraft Studio6 小时前
【案例分享】如何借助JS UI组件库DHTMLX Suite构建高效物联网IIoT平台
javascript·物联网·ui
打小就很皮...6 小时前
HBuilder 发行Android(apk包)全流程指南
前端·javascript·微信小程序
集成显卡7 小时前
PlayWright | 初识微软出品的 WEB 应用自动化测试框架
前端·chrome·测试工具·microsoft·自动化·edge浏览器
前端小趴菜058 小时前
React - 组件通信
前端·react.js·前端框架