javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > JavaScript解决跨域

JavaScript解决跨域的三种方法小结

作者:好好吃饭e

在Web应用中,当一个网页的脚本试图去请求另一个域名下的资源时,就会遇到跨域问题,跨域问题是由浏览器的同源策略所引起的,本文给大家介绍了JavaScript解决跨域的三种方法,需要的朋友可以参考下

前言

什么是跨域问题

在Web应用中,当一个网页的脚本试图去请求另一个域名下的资源时,就会遇到跨域问题。跨域问题是由浏览器的同源策略所引起的。换句话说:后端返回给浏览器的数据会被浏览器的同源策略给拦截下来。

同源策略要求资源的协议、域名和端口号都必须相同,才能确保数据的安全性。如果不满足这个条件,请求将被浏览器拒绝,从而导致跨域问题的出现。

协议号:域名:端口号 / 路径

https://192.168.31.45:8080/user

https://192.168.31.45:8080/list

上面这个例子虽然它们的路径不一样但是协议号、域名、端口号都相同,所以它们就是同源的

跨域问题的原因

跨域问题主要是由于浏览器的安全策略限制引起的。同源策略的目的是保护用户的隐私和数据安全,防止恶意网站获取用户的敏感信息或进行未授权的操作。 通过限制跨域请求,浏览器有效地减少了许多网络攻击的风险,例如跨站脚本攻击(XSS)和跨站请求伪造(CSRF)。

JSONP

JSONP(JSON with Padding)是一种用于解决跨域请求的技术,它利用了 <script> 标签可以跨域加载资源的特性。

下面是 JSONP 解决跨域请求的基本原理:

前端代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <button id="btn">获取数据</button>
  <script>
    // 定义一个函数 jsonp,用于发送 JSONP 请求
    function jsonp(url, cb) {
      return new Promise((resolve, reject) => {
        // 创建一个 script 标签
        const script = document.createElement('script');
        
        // 设置 script 的 src 属性,包含了请求的 URL 和回调函数名称
        script.src = `${url}?cb=${cb}`; // http://localhost:3000?cb='callback'
        
        // 将 script 添加到文档中
        document.body.appendChild(script); // 浏览器自动请求 src 中的内容
        
        // 定义一个全局函数,用于处理返回的数据
        window[cb] = (data) => {
          resolve(data)
        }
      })
    }
    
    // 获取按钮元素
    let btn = document.getElementById('btn');
    
    // 绑定点击事件
    btn.addEventListener('click', () => {
      // 发送 JSONP 请求
      jsonp('http://localhost:3000', 'callback')
      .then(res => {
        console.log('后端的返回结果:' + res);
      })

    })
  </script>
</body>
</html>

后端代码:

const Koa = require('koa');
const app = new Koa();

// 定义中间件函数 main,处理请求并返回数据
const main = (ctx, next) => {
  console.log(ctx.query); // 输出请求参数对象 { cb: 'callback' }
  
  // 从请求参数中获取回调函数名称
  const cb = ctx.query.cb;

  // 准备要返回给前端的数据
  const data = '给前端的数据';
  
  // 构造带有回调函数名称的字符串,格式为 'callback("给前端的数据")'
  const str = `${cb}('${data}')`;
  
  // 将构造好的字符串作为响应体返回给前端
  ctx.body = str;
}

// 将 main 中间件注册到 Koa 应用中
app.use(main);

// 监听 3000 端口,启动服务器
app.listen(3000, () => {
  console.log('listening on port 3000');
})

优点:

缺点:

CORS(跨域资源共享)

CORS是一种机制,允许服务器在响应中携带一个特殊的标头,以告知浏览器该服务器允许哪些源的网页访问其资源。 可以总结为一句话:后端通过设置响应头来告诉浏览器不要拒绝接受后端的响应。

前端代码:在用户点击按钮时,通过发送跨域请求获取服务器返回的数据,并将数据打印到浏览器的控制台

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <button id="btn">获取数据</button>

  <script>
    let btn = document.getElementById('btn');
    btn.addEventListener('click', () => {
      fetch('http://localhost:3000')  // 发送跨域请求到服务器
      .then(res => res.json())
      .then((res) => {
        console.log(res);  // 打印返回的数据到控制台
      })
    })

  </script>
</body>
</html>

代码实现了以下功能:

后端代码 :Node.js 服务器代码,创建了一个 HTTP 服务器,监听在端口 3000。当接收到请求时,返回一个包含 "hello cors" 消息的 JSON 数据。

const http = require('http');

const server = http.createServer((req, res) => {
  res.writeHead(200, {
     // cros实现原理
    'Access-Control-Allow-Origin': 'http://127.0.0.1:5500'  // 允许来自指定地址的跨域请求
  })

  let data = {
    msg: "hello cors"
  }
  res.end(JSON.stringify(data)) // 返回数据给前端页面
})

server.listen(3000, () => {
  console.log('listening on port 3000');
})

后端代码第6行在服务端设置响应头来控制跨域访问

常见的响应头包括:

CORS支持各种类型的HTTP请求,包括GET、POST等。

domain

我们还可以使用 Domain 方法来解决一些特定情况下的跨域访问问题。 在跨域通信时,还需要注意以下几点:

下面举一个简单的例子来说明 Domain 方法的用法:

假设有两个页面分别位于不同子域名下,一个是 parent.example.com,另一个是 child.example.com。我们希望这两个页面能够进行跨域通信。

在父级页面 parent.example.com/index.html 中的代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Parent Page</title>
</head>
<body>
  <h1>Parent Page</h1>
  <iframe src="http://child.example.com/child.html"></iframe>
  
  <script>
    document.domain = 'example.com';
    var messageFromParent = 'Hello from parent page!';
  </script>
</body>
</html>

在子级页面 child.example.com/child.html 中的代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Child Page</title>
</head>
<body>
  <h1>Child Page</h1>
  
  <script>
    document.domain = 'example.com';
    var messageFromChild = 'Hello from child page!';
    
    // 访问父级页面定义的变量
    var message = window.parent.messageFromParent;
    console.log('Message from parent: ' + message);
  </script>
</body>
</html>

在这个例子中,父级页面和子级页面分别设置了相同的 document.domain 为 'example.com',以实现二级域名相同。

父级页面定义了一个名为 messageFromParent 的变量,子级页面在加载后通过 window.parent 来访问父级页面定义的变量,并打印出父级页面的消息。

通过设置相同的 document.domain,父子页面之间就可以进行跨域通信,实现数据共享和交互。

postMessage

使用 postMessage() 方法结合 <iframe> 元素可以实现跨域通信,这是一种常见的技术。通过在父窗口和嵌套的 <iframe> 之间使用 postMessage() 方法,可以安全地在不同源之间进行通信。

<iframe> 可以用于解决跨域通信的问题,其原理是利用浏览器中同源策略的限制,将不同域的内容加载到独立的 <iframe> 中,通过 postMessage 方法进行跨文档通信。

在 a.html 文件中:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <h2>a.html</h2>

  <!-- 创建一个 iframe 元素来加载 b.html -->
  <iframe src="http://127.0.0.1:5500/postMessage/b.html" frameborder="0" id="iframe"></iframe>

  <script>
    // 向 b.html 发送数据
    let iframe = document.getElementById('iframe');
    iframe.onload = function() {
      // 准备要发送的数据
      let data = {
        name: 'Tom'
      };
      // 通过 postMessage 方法向 iframe 发送数据
      iframe.contentWindow.postMessage(JSON.stringify(data), 'http://127.0.0.1:5500');
    }

    // 监听来自 b.html 的消息
    window.addEventListener('message', function(e) {
      console.log(e.data);
    });
  </script>
</body>
</html>

在 b.html 文件中:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <h4>b.html</h4>

  <script>
    // 监听来自父页面的消息
    window.addEventListener('message', function(e) {
      console.log(JSON.parse(e.data));

      if (e.data) {
        // 收到消息后延迟 2 秒发送回应给父页面
        setTimeout(function() {
          window.parent.postMessage('我接受到', 'http://127.0.0.1:5500');
        }, 2000);
      }
    });
  </script>
</body>
</html>

优点:

缺点:

以上就是JavaScript解决跨域的三种方法的详细内容,更多关于JavaScript解决跨域的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文