什么是跨域?如何解决跨域问题?

跨域是浏览器的安全机制,阻止不同源之间的请求。解决方案包括 CORS、JSONP、代理服务器和使用 postMessage API。

浏览器机制 中等 跨域 CORS 浏览器安全

什么是跨域?

跨域是指浏览器因同源策略而阻止不同源之间的网络请求的行为。当请求的 URL 与当前页面的 URL 在协议(http/https)、域名(如 example.com)或端口(如 8080)中任意一项不同时,就构成跨域。跨域问题本质是浏览器强制实施的安全机制,目的是防止恶意网站窃取或篡改用户敏感数据,例如 Cookie、LocalStorage 或 Ajax 请求。

为什么有跨域限制?

源于同源策略(Same-Origin Policy),这是一种全局性安全限制:

  • 约束资源交互:仅允许同源网页脚本访问数据和资源。
  • 保护作用:防止跨站脚本攻击(XSS)或数据泄露。 跨域限制仅在浏览器环境中存在,例如 JavaScript 的 Ajax 请求会被拦截。

如何解决跨域问题?

解决思路聚焦于突破浏览器的同源策略限制,常见方法如下:

1. CORS(跨域资源共享)

CORS 是最推荐的方式,需要服务端响应额外头部字段:

  • 实现方法:服务端在响应头中添加 Access-Control-Allow-Origin 字段,允许指定源地址访问。
    // 示例响应头:  
    Access-Control-Allow-Origin: *              // 允许所有域  
    Access-Control-Allow-Methods: GET, POST     // 允许多种请求方法  
    Access-Control-Allow-Headers: Authorization // 允许自定义头部  
    

    在服务端支持场景:

  • Spring Boot 使用注解 @CrossOrigin 处理特定端点配置。
  • Express.js 等通过中间件设置响应头。

2. JSONP(JSON with Padding)

JSONP 利用 <script> 标签加载数据的特性绕过跨域限制:

  • 前端实现:动态创建 script 元素,后端返回数据封装于回调函数。
    <script>
    function handleResponse(data) { 
      console.log("Received:", data); 
    }
    </script>
    <script src="http://api.example.com/data?callback=handleResponse"></script>
    
  • 后端实现:Node.js 拼接回调函数与数据。
    // Node.js 服务器代码示例
    const http = require('http');
    http.createServer((req, res) => {
      const callback = req.url.split('callback=').split('&');
      const data = JSON.stringify({ status: "success" });
      res.end(`${callback}(${data})`);
    }).listen(3000);
    

    缺点:仅支持 GET 请求。

3. 代理服务器

通过代理将跨域请求中转为本域请求:

  • 反向代理 (如 Nginx):Nginx 接受前端请求并访问后端服务。
    server {
      listen 80;
      server_name localhost;
      location /api {
          proxy_pass http://api:9090;
          proxy_set_header Host $host;
      }
    }
    
  • 开发代理 (如 Webpack):在 webpack.config.js 设置开发代理。
    module.exports = {
      devServer: {
          proxy: {
              '/api': 'http://localhost:9090'
          }
      }
    };
    

4. Document.domain + iframe

用于同主域下的子域协作场景:

  • 在父页面及 iframe 页面均设置 document.domain 为主域名。
    document.domain = "example.com";  // 前后端子域需设置一致
    

    确保所有页面均同意域名后实现通信。

5. Nginx 或网关统一配置

服务端直接管理跨域规则,配置网关实现全局放行:

# 示例 (Spring Gateway application.yml):

spring.cloud.gateway.globalcors:
    corsConfigurations:
        '[/**]': 
            allowedOrigins: "http://localhost:8090"
            allowedMethods: "GET, POST"
            allowedHeaders: "*"
            maxAge: 3600

支持前端域名调用后端服务。

其它补充方法

  • PostMessage API:用于窗口间安全跨源数据通信。
  • WebSocket 协议:原生支持不同域间的客户端与服务器通讯。
  • 禁用浏览器安全策略(仅限开发环境):通过浏览器配置文件临时关闭策略限制。