同源策略,解决跨域的方法

跨域是由于浏览器的同源策略导致的,即不同域名、协议或端口之间的网页脚本不能相互访问。为了解决跨域问题,常见的方法包括:

  • JSONP(只支持 GET 请求):JSONP 是一种利用 <script> 标签可以跨域加载资源的特性来实现跨域请求的方法。它的原理是在客户端动态创建一个 <script> 标签,标签的 src 属性指向服务器的 API 地址,并且传递一个回调函数名作为参数,服务器返回的数据将会作为参数传入回调函数中。由于 <script> 标签可以跨域加载资源,因此可以获取到服务器返回的数据。代码示例:
<!-- 客户端 HTML 页面 -->
<script>
  function handleResponse(data) {
    console.log(data); // 处理服务器返回的数据
  }
</script>
<script src="http://api.example.com/data?callback=handleResponse"></script>

// 服务器返回的数据
handleResponse({"name": "John", "age": 30});

封装一个简单的 JSONP 请求函数可以使用 Promise 来处理异步操作,并动态创建一个 <script> 标签来实现跨域请求。以下是一个简单的 JSONP 封装示例:

function jsonp(url, params) {
  // 生成一个唯一的回调函数名
  const callbackName = `jsonp_callback_${Date.now()}`;

  // 将参数拼接到 URL 中
  const queryParams = new URLSearchParams(params);
  url += `${url.includes('?') ? '&' : '?'}${queryParams.toString()}`;

  return new Promise((resolve, reject) => {
    // 创建回调函数
    window[callbackName] = function (data) {
      resolve(data);

      // 请求完成后删除回调函数和 <script> 标签
      delete window[callbackName];
      script.parentNode.removeChild(script);
    };

    // 创建 <script> 标签,并设置其 src 属性
    const script = document.createElement('script');
    script.src = `${url}&callback=${callbackName}`;

    // 加载失败处理
    script.onerror = () => {
      reject(new Error('JSONP request failed'));
      delete window[callbackName];
      script.parentNode.removeChild(script);
    };

    // 将 <script> 标签添加到文档中,触发请求
    document.body.appendChild(script);
  });
}
// 使用示例:
// 请求 JSONP 数据
jsonp('http://api.example.com/data', { key: 'value' })
  .then(data => {
    console.log(data); // 处理服务器返回的数据
  })
  .catch(error => {
    console.error(error);
  });

  • CORS(Cross-Origin Resource Sharing):CORS 是一种基于 HTTP 头部的机制,允许服务器声明哪些域名可以访问它的资源。在客户端发送请求时,浏览器会自动附加 Origin 头部,并且在响应中会包含 Access-Control-Allow-Origin 头部,用于指示是否允许特定的域名访问资源。代码示例(使用 Express 框架):
// 服务器端代码
const express = require('express');
const app = express();

// 设置允许跨域访问的域名(注意:如果使用 *,表示允许任意域名访问)
app.use((req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', 'http://example.com');
  next();
});

// 处理跨域请求
app.get('/data', (req, res) => {
  const data = { name: 'John', age: 30 };
  res.json(data);
});

app.listen(3000, () => {
  console.log('Server is running on http://localhost:3000');
});
<!-- 客户端 HTML 页面 -->
<script>
  fetch('http://api.example.com/data')
    .then(response => response.json())
    .then(data => console.log(data)); // 处理服务器返回的数据
</script>

  • 代理服务器:使用代理服务器是另一种解决跨域问题的方法。在客户端发送请求时,将请求发送给自己的服务器,然后由服务器去请求目标服务器的资源,最后将目标服务器的响应返回给客户端。由于请求是发送给同源的服务器,因此不存在跨域问题。代码示例(使用 Express 框架):
// 服务器端代码
const express = require('express');
const axios = require('axios');
const app = express();

// 处理跨域请求
app.get('/data', async (req, res) => {
  try {
    const response = await axios.get('http://api.example.com/data');
    res.json(response.data);
  } catch (error) {
    res.status(500).json({ error: 'An error occurred' });
  }
});

app.listen(3000, () => {
  console.log('Server is running on http://localhost:3000');
});

<!-- 客户端 HTML 页面 -->
<script>
  fetch('http://localhost:3000/data')
    .then(response => response.json())
    .then(data => console.log(data)); // 处理服务器返回的数据
</script>

  • WebSocket是一种全双工通信协议,它建立在TCP上,可以在浏览器和服务器之间创建持久连接,实现实时的双向数据传输。WebSocket不受同源策略的限制,可以在任意域名下建立连接。
//在浏览器端使用JavaScript代码创建WebSocket对象,并指定要连接的服务器地址:
const socket = new WebSocket('ws://example.com'); // 注意使用ws协议,而不是http或https
//通过WebSocket对象的事件处理函数来处理连接和消息:
socket.onopen = () => {
  console.log('WebSocket连接已打开');
};

socket.onmessage = event => {
  console.log('收到消息:', event.data);
};

socket.onclose = () => {
  console.log('WebSocket连接已关闭');
};

socket.onerror = error => {
  console.error('WebSocket发生错误:', error);
};
//通过WebSocket对象的方法发送消息到服务器:
socket.send('Hello, server!');

//服务器端也需要实现WebSocket协议来处理客户端的连接和消息。
  • postMessage是HTML5中提供的一种跨文档通信的方法,它允许一个窗口与另一个窗口进行安全的跨域通信。使用postMessage,可以在一个页面中发送消息到另一个页面,无论这两个页面是否同源。在postMessage中,第一个参数是要发送的消息,第二个参数是目标窗口的origin,用来限制只接收来自特定域的消息,防止恶意代码的攻击。
  • 在发送消息的页面中,使用postMessage方法向目标窗口发送消息:
// 发送消息到目标窗口
window.postMessage('Hello from Page A!', 'https://example.com');
  • 在目标页面中,监听message事件来接收消息:
// 监听message事件来接收消息
window.addEventListener('message', event => {
  // 判断消息来源是否可信,防止恶意代码
  if (event.origin === 'https://example.com') {
    console.log('收到消息:', event.data);
    // 可以在这里处理接收到的消息
  }
});

这些方法可以根据具体的情况来选择使用,以解决不同场景下的跨域问题。

全部评论

相关推荐

评论
1
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务