跨域问题

一、跨域本质与同源策略

跨域触发条件:当请求的 URL 与当前页面的协议、域名、端口任一不同时。

同源策略限制范围

  • AJAX/Fetch 请求
  • Web 字体加载
  • Web Workers
  • Canvas 图像操作
  • Cookie/LocalStorage 访问

浏览器控制台报错
Access-Control-Allow-Origin header is present on the requested resource


二、9 大跨域解决方案

1. CORS (跨域资源共享) - 主流方案
// 服务端设置响应头
res.setHeader('Access-Control-Allow-Origin', 'https://client.com');
res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type,Authorization');
res.setHeader('Access-Control-Allow-Credentials', 'true'); // 允许携带cookie

// 预检请求处理
if (req.method === 'OPTIONS') {
  res.status(200).end();
  return;
}

CORS 类型

  • 简单请求:GET/POST/HEAD + 标准头
  • 预检请求:需先发 OPTIONS 请求验证
2. JSONP - 传统方案
<!-- 前端 -->
<script>
  function handleResponse(data) {
    console.log('Received:', data);
  }
</script>
<script src="https://api.com/data?callback=handleResponse"></script>

<!-- 后端响应 -->
handleResponse({"name": "John", "age": 30});

限制:仅 GET 请求,无错误处理,XSS 风险

3. Nginx 反向代理
server {
  listen 80;
  server_name client.com;

  location /api/ {
    proxy_pass http://api-server.com; # 代理到目标服务器
    proxy_set_header Host $host;
    add_header 'Access-Control-Allow-Origin' '*';
  }
}
4. WebSocket - 双向通信
const socket = new WebSocket('wss://api.com');

socket.onopen = () => {
  socket.send(JSON.stringify({ action: 'subscribe' }));
};

socket.onmessage = (event) => {
  console.log('Data:', JSON.parse(event.data));
};
5. postMessage - 跨窗口通信
// 父窗口 (https://parent.com)
iframe.contentWindow.postMessage('Hello', 'https://child.com');

// 子窗口 (https://child.com)
window.addEventListener('message', (event) => {
  if (event.origin !== 'https://parent.com') return;
  console.log('Received:', event.data);
});
6. 代理服务器 (Node.js)
const axios = require('axios');

app.get('/proxy', async (req, res) => {
  const response = await axios.get('https://api.com/data', {
    params: req.query,
  });
  res.json(response.data);
});
7. document.domain - 子域跨域
// parent.parent.com
document.domain = 'parent.com';

// child.parent.com
document.domain = 'parent.com'; // 现在可以互相访问
8. 浏览器禁用安全策略 - 仅开发环境
# Chrome启动参数
chrome.exe --disable-web-security --user-data-dir="C:\temp"
9. CDN 代理 + CORS
<script src="https://cdn.com/cors-proxy?url=https://api.com/data"></script>

三、方案对比与选型

方案 适用场景 优点 缺点
CORS 主流 API 交互 标准化、安全可控 需服务端配合
Nginx 代理 生产环境部署 高性能、配置灵活 运维复杂度增加
JSONP 老旧浏览器兼容 兼容性好 仅 GET、安全性低
WebSocket 实时双向通信 全双工、高效 协议升级复杂
postMessage 跨窗口/iframe 通信 安全隔离 仅窗口间通信

四、面试高频问题

  1. CORS 预检请求何时触发?

    • 使用非简单方法(PUT/DELETE)
    • 包含自定义头(Authorization)
    • Content-Type 非标准值
  2. 如何携带 Cookie 跨域?

    // 前端
    fetch(url, { credentials: 'include' });
    
    // 服务端
    res.setHeader('Access-Control-Allow-Credentials', 'true');
    res.setHeader('Access-Control-Allow-Origin', 'https://exact.com'); // 不能为*
    
  3. OPTIONS 请求是什么?
    预检请求,检查服务器是否允许实际请求

  4. JSONP 为什么不安全?

    • 无错误处理机制
    • 可能执行恶意脚本
    • 易受 CSRF 攻击
  5. 生产环境最佳实践?

    • 主域相同用 CORS
    • 不同域用 Nginx 代理
    • 敏感操作加 CSRF Token

五、安全增强方案

  1. CORS 白名单控制

    const allowedOrigins = ['https://client.com', 'https://app.com'];
    if (allowedOrigins.includes(req.headers.origin)) {
      res.setHeader('Access-Control-Allow-Origin', req.headers.origin);
    }
    
  2. CSRF Token 防护

    // 服务端生成并下发
    res.cookie('csrf_token', generateToken(), { httpOnly: true });
    
    // 前端在请求头携带
    fetch(url, {
      headers: { 'X-CSRF-Token': getCookie('csrf_token') },
    });
    
  3. CSP 增强防御

Content-Security-Policy: default-src 'self'; script-src trusted.com

六、面试回答策略

  1. 分层解析

    "跨域本质是浏览器安全策略,解决核心在于:绕过限制(JSONP)或获得授权(CORS)。现代项目首选 CORS,需前后端协同实现"

  2. 场景化选型

    "在电商项目中,主站和 API 网关同域用 CORS,第三方支付用 postMessage,实时通知用 WebSocket"

  3. 安全深度

    "配置 CORS 时我们采用动态白名单+CSRF Token 双验证,避免使用通配符*,并对 OPTIONS 请求做速率限制"

  4. 性能优化

    "通过 Nginx 代理将多个跨域请求合并,减少预检请求次数,预检结果缓存 24 小时(Access-Control-Max-Age)"

  5. 特殊场景

    "跨域文件上传需注意:

    • 预检请求包含Content-Type: multipart/form-data
    • 服务器处理 OPTIONS 时返回Access-Control-Allow-Headers: content-type"
  6. 框架实践

    // Express中间件
    app.use(
      cors({
        origin: config.allowedOrigins,
        methods: ['GET', 'POST'],
        allowedHeaders: ['Content-Type', 'Authorization'],
        maxAge: 86400,
      })
    );
    

💡 面试金句
"跨域不是技术障碍而是安全特性。现代浏览器为 CORS 提供完备支持,配合服务端精细化的权限控制,既能保障安全又能实现灵活的资源共享。关键在于理解协议细节,避免一刀切的通配符配置。"

Copyright © Jun 2025 all right reserved,powered by Gitbook该文件修订时间: 2025-07-03 17:35:08

results matching ""

    No results matching ""

    results matching ""

      No results matching ""