Skip to main content

跨域配置

浏览器的跨域(Cross-Origin)问题源于浏览器的同源策略(Same-Origin Policy),这是一种重要的安全机制。以下从原理、限制、解决方案等方面详细解析:

一、同源策略:跨域限制的根源

1. 什么是同源?

当两个URL的协议(Protocol)、域名(Domain)、端口(Port) 完全相同时,视为同源。例如:

  • 同源:https://example.comhttps://example.com/path
  • 跨域:https://example.comhttp://example.com(协议不同)
  • 跨域:https://example.comhttps://api.example.com(域名不同)
  • 跨域:https://example.com:8080https://example.com:80(端口不同)

2. 同源策略的限制范围

同源策略限制以下跨域操作:

  • AJAX/Fetch请求:无法直接获取跨域接口的响应数据。
  • DOM访问:无法读取跨域页面的DOM节点(如iframe嵌套的页面)。
  • Cookie/Session:跨域请求时无法自动携带同源的Cookie。

二、跨域请求的常见场景

  1. 前后端分离开发:前端运行在 http://localhost:3000,后端API在 http://api.example.com
  2. 第三方服务集成:页面嵌入其他域名的API(如地图、支付接口)。
  3. CDN资源加载:CSS/JS/图片等资源来自不同域名的CDN(例外:浏览器对静态资源的跨域限制较宽松,但某些操作仍受限)。

三、跨域问题的具体表现

当浏览器发起跨域请求时,控制台会报错:

Access to fetch at 'https://api.example.com/data' from origin 'https://your-site.com' 
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present
on the requested resource.

核心原因:服务器未返回允许跨域的响应头,浏览器拒绝解析响应数据。

四、跨域解决方案

1. 最推荐方案:CORS(跨域资源共享)

原理:通过服务器返回特定响应头,告知浏览器允许跨域请求。
服务器配置(以Node.js为例)

const express = require('express');
const app = express();

// 允许所有域名跨域(开发环境可用,生产环境建议指定具体域名)
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*'); // * 表示允许所有域名
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
// 允许携带Cookie时,不能使用*,需指定具体域名
// res.setHeader('Access-Control-Allow-Origin', 'https://your-site.com');
// res.setHeader('Access-Control-Allow-Credentials', 'true');
next();
});

关键响应头说明

  • Access-Control-Allow-Origin:允许的源(域名),* 表示所有域名。
  • Access-Control-Allow-Credentials:是否允许携带Cookie(需与Origin配合,不能用*)。
  • Access-Control-Allow-Methods:允许的HTTP方法(如GET、POST)。
  • Preflight请求:复杂请求(如PUT、自定义头)会先发送OPTIONS预检请求,服务器需响应允许的策略。

2. 兼容旧浏览器:JSONP(JSON with Padding)

原理:利用<script>标签无跨域限制的特性,动态加载跨域数据。
前端实现

function fetchData(url, callback) {
const script = document.createElement('script');
script.src = `${url}?callback=jsonpCallback`;
document.body.appendChild(script);

// 定义回调函数
window.jsonpCallback = function(data) {
callback(data);
document.body.removeChild(script);
delete window.jsonpCallback;
};
}

// 使用示例
fetchData('https://api.example.com/jsonp', (data) => {
console.log(data);
});

服务器响应

// 响应内容需包裹在回调函数中
jsonpCallback({ "data": "success" });

局限性

  • 仅支持GET请求,无法发送POST等其他方法。
  • 存在XSS风险(需确保回调函数名不被篡改)。

3. 前端代理:开发环境常用(如Webpack、Vite)

原理:在开发服务器中设置代理,将跨域请求转发到目标服务器,规避浏览器限制。
Vite代理配置示例(vite.config.js)

export default {
server: {
proxy: {
'/api': {
target: 'https://api.example.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
}
};

前端请求

fetch('/api/data').then(res => res.json()); // 实际请求 https://api.example.com/data

适用场景:仅用于开发环境,生产环境需配合后端代理或CORS。

4. 后端代理

原理:在服务器端(如Nginx)设置反向代理,将跨域请求转发至目标域名。
Nginx配置示例

server {
listen 80;
server_name your-site.com;

location /api/ {
proxy_pass https://api.example.com/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}

5. 其他方案(较少用)

  • PostMessage:用于iframe跨域通信,通过window.postMessage传递数据。
  • Node中间层:前端请求本地Node服务,由Node服务转发跨域请求(适用于前后端同构项目)。
  • WebSocket:基于TCP协议,不受同源策略限制,但需服务器支持WebSocket协议。

五、跨域携带Cookie的注意事项

  1. 前端需设置withCredentials: true
fetch('https://api.example.com', {
method: 'GET',
credentials: 'include' // 携带同源Cookie
});
  1. 服务器响应头需满足:
    • Access-Control-Allow-Origin不能为*,必须指定具体域名。
    • 必须包含Access-Control-Allow-Credentials: true

六、跨域资源加载(静态资源)

浏览器对CSS、JS、图片等静态资源的跨域限制较宽松,但某些操作仍需处理:

  • 跨域脚本执行:默认允许加载,但无法通过document.scripts获取内容。
  • 跨域图片用于Canvas:若图片跨域且未设置Cross-Origin头,Canvas会被污染,无法导出。
  • 解决方案:服务器为静态资源添加Access-Control-Allow-Origin头。

七、总结:跨域的核心原则

  1. 同源策略是浏览器的安全基石,跨域限制是为了防止恶意网站窃取用户数据。
  2. 解决方案的核心在服务器:无论是CORS、代理还是JSONP,都需要服务器配合。
  3. 开发环境与生产环境的策略差异:开发时可用前端代理,生产环境建议使用CORS或后端代理。
  4. 安全性优先:避免在生产环境使用Access-Control-Allow-Origin: *,应指定具体域名,并谨慎处理Cookie。

理解跨域原理后,可根据项目需求选择合适的方案,平衡安全性和开发效率。