Skip to content

跨域是什么

跨域是指浏览器中的 同源策略 限制了不同源(domain、protocol、port)之间的请求与资源访问。在 Web 开发中,当一个网站的脚本尝试访问另一个网站的资源时,浏览器会基于 同源策略(Same-Origin Policy, SOP)来限制这种跨域请求。

什么是同源策略?

同源策略要求 协议、域名和端口号必须完全相同,否则浏览器就认为是跨域请求。比如,下面这两个 URL 是不同源的:

  • http://example.com/page1
  • https://example.com/page2

虽然这两个 URL 使用相同的域名,但由于协议不同(HTTP vs HTTPS),它们被认为是不同源,因此不能直接进行交互。

为什么会有跨域问题?

同源策略的主要目的是 保护用户的隐私和安全。它防止了如下情况的发生:

  • 网站 A 的 JavaScript 可以访问网站 B 的数据,导致用户的敏感信息被窃取。
  • 恶意网站通过脚本访问用户在其他网站上的私人数据(如银行账户、社交账户等)。

跨域的常见场景

  1. AJAX 请求跨域:从一个域名的网页通过 JavaScript 发起请求到另一个域名(如:A 网站访问 B 网站的 API)。
  2. 图片、脚本、样式等资源:一个网站的资源请求来自于另一个域名。
  3. iframe 嵌套:一个网站嵌入了来自其他域名的网页,并希望进行交互。

如何解决跨域问题

有多种方法可以解决跨域问题,具体解决方案取决于应用的场景和要求。常见的跨域解决方法包括:


1. CORS(跨源资源共享)

CORS(Cross-Origin Resource Sharing) 是一种浏览器技术,它允许服务器声明哪些源可以访问资源。通过设置 HTTP 头部(如 Access-Control-Allow-Origin),服务器可以告诉浏览器允许哪些来源进行跨域请求。

如何实现 CORS

  • 服务器端设置:服务器需要响应 HTTP 请求头,允许跨域请求。
http
Access-Control-Allow-Origin: *
  • 允许特定来源:你可以设置允许特定的源进行跨域访问,而不是允许所有来源。
http
Access-Control-Allow-Origin: https://example.com
  • 其他常见的 CORS 头部

    • Access-Control-Allow-Methods: 允许的方法,如 GET, POST, PUT.
    • Access-Control-Allow-Headers: 允许请求携带的头部信息,如 Content-Type.
    • Access-Control-Allow-Credentials: 是否允许发送凭据(cookies 或 HTTP 认证信息)。

CORS 具体工作流程

  1. 浏览器发起跨域请求,并发送一个带有 Origin 头部的请求。
  2. 服务器检查请求的 Origin,如果允许跨域,返回带有相应的 Access-Control-Allow-Origin 头部的响应。
  3. 浏览器根据响应头部来决定是否允许该请求的结果被使用。

2. JSONP(JSON with Padding)

JSONP 是一种跨域请求的方法,主要用于 GET 请求,通过在页面中动态插入 <script> 标签来获取跨域的数据。JSONP 的核心思想是将请求的数据包装在一个函数中,脚本加载完成后立即调用该函数并传递数据。

如何实现 JSONP

html

<script src="https://example.com/api/data?callback=handleData"></script>
<script>
    function handleData(data) {
        console.log(data);  // 处理返回的数据
    }
</script>

JSONP 的限制

  • 只支持 GET 请求:因为 <script> 标签只支持 GET 请求,不能进行其他 HTTP 方法的跨域请求。
  • 安全问题:JSONP 的实现方式存在一定的安全隐患,因为它通过动态插入 <script> 标签来获取数据,这意味着可能会被恶意脚本攻击。

3. 代理转发(Proxy)

通过设置一个代理服务器来转发请求,可以解决前端请求的跨域问题。在开发过程中,可以使用代理服务器将请求发送到目标服务器,而不会受到浏览器的跨域限制。

如何实现代理转发

  • 前端开发环境中,你可以通过配置 webpackvite 等开发工具的代理功能来解决跨域问题。

例如,使用 webpack 配置代理:

js
// webpack.config.js
module.exports = {
    devServer: {
        proxy: {
            '/api': 'http://backend-server.com',
        },
    },
};

在这个配置中,所有发往 /api 的请求都会被代理到 http://backend-server.com,这样前端和后端的请求就不会受到跨域的限制。


4. 服务器端代理(后端代理)

在生产环境中,可以通过 服务器端代理 来解决跨域问题。前端向自己的服务器发起请求,然后由服务器代理转发请求到实际的目标服务器。

如何实现服务器端代理

  • Node.js 服务器端代理
js
const express = require('express');
const app = express();
const axios = require('axios');

app.get('/api/data', async (req, res) => {
    try {
        const response = await axios.get('https://external-api.com/data');
        res.json(response.data);
    } catch (error) {
        res.status(500).send('Error fetching data');
    }
});

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

在这个例子中,前端请求 /api/data,然后后端代理将请求转发到实际的目标 API。


5. WebSocket

WebSocket 是一种在浏览器和服务器之间进行双向通信的协议,它不受同源策略的限制。因此,可以使用 WebSocket 来进行跨域通信。

如何使用 WebSocket

javascript
const socket = new WebSocket('wss://example.com/socket');

socket.onopen = () => {
    socket.send('Hello Server!');
};

socket.onmessage = (event) => {
    console.log('Received message:', event.data);
};

WebSocket 建立连接后,浏览器和服务器之间可以自由地交换消息,而不受同源策略的限制。


6. 使用 iframe 和 postMessage

通过将一个页面嵌入到 iframe 中,并使用 postMessage 方法进行跨域通信。postMessage 是一种安全的方式,可以跨越源的限制来进行消息传递。

如何使用 postMessage

html
<!-- parent.html -->
<iframe id="iframe" src="https://other-domain.com"></iframe>

<script>
    const iframe = document.getElementById('iframe');
    iframe.contentWindow.postMessage('Hello from parent', 'https://other-domain.com');
</script>
javascript
// child.html (https://other-domain.com)
window.addEventListener('message', (event) => {
    if (event.origin !== 'https://your-domain.com') return;  // 安全验证
    console.log('Received message:', event.data);
});

总结

  • 跨域问题 是由于浏览器的同源策略(SOP)造成的,限制了不同源之间的交互。
  • CORS 是目前最常用的跨域解决方案,通过设置响应头部来允许指定源进行跨域请求。
  • JSONP 是通过 <script> 标签来实现跨域,只支持 GET 请求。
  • 代理转发服务器端代理 通过中间层解决了跨域问题,前端和后端之间的请求不会受同源策略的限制。
  • WebSocketpostMessage 是其他解决跨域的方案,通常用于实时通信和嵌套的 iframe 中。

跨域问题的解决方法有很多,具体选择哪种方法取决于项目的需求、环境和安全考虑。