阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 跨域处理方案

跨域处理方案

作者:陈川 阅读数:59964人阅读 分类: Node.js

跨域问题的本质

跨域问题源于浏览器的同源策略限制。同源策略要求协议、域名和端口完全相同才能自由通信。不同源的请求会被浏览器拦截,导致前端无法获取响应数据。常见的跨域场景包括前后端分离开发、调用第三方API、子域名不同等。

JSONP方案

JSONP利用<script>标签不受同源策略限制的特性实现跨域请求。客户端定义一个回调函数,服务器返回调用该函数的JavaScript代码。

// 客户端代码
function handleResponse(data) {
  console.log('Received data:', data);
}

const script = document.createElement('script');
script.src = 'http://example.com/api?callback=handleResponse';
document.body.appendChild(script);

// 服务器响应
handleResponse({data: "some data"});

缺点:

  • 仅支持GET请求
  • 安全性较差
  • 错误处理困难

CORS方案

CORS(跨域资源共享)是现代浏览器支持的标准化跨域解决方案。服务器通过设置响应头来声明允许的跨域请求。

简单请求

满足以下条件即为简单请求:

  • 方法为GET/HEAD/POST
  • Content-Type为text/plain、multipart/form-data或application/x-www-form-urlencoded
// 服务器设置
app.use((req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', 'http://client-domain.com');
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST');
  next();
});

预检请求

不满足简单请求条件的请求会先发送OPTIONS预检请求。

// 服务器处理预检请求
app.options('/api', (req, res) => {
  res.setHeader('Access-Control-Allow-Origin', 'http://client-domain.com');
  res.setHeader('Access-Control-Allow-Methods', 'PUT, DELETE');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  res.status(204).end();
});

携带凭证的请求

需要额外设置Access-Control-Allow-Credentials头:

// 客户端
fetch('http://api.example.com', {
  credentials: 'include'
});

// 服务器
res.setHeader('Access-Control-Allow-Credentials', 'true');

代理服务器方案

通过同源的后端服务器转发请求,绕过浏览器限制。Node.js实现示例:

const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');

const app = express();

app.use('/api', createProxyMiddleware({
  target: 'http://target-server.com',
  changeOrigin: true,
  pathRewrite: {
    '^/api': ''
  }
}));

app.listen(3000);

WebSocket跨域

WebSocket协议不受同源策略限制,但服务器需要显式允许跨域连接:

// 客户端
const socket = new WebSocket('ws://server.example.com');

// Node.js服务器
const WebSocket = require('ws');
const wss = new WebSocket.Server({
  port: 8080,
  verifyClient: (info, done) => {
    // 验证origin
    done(info.origin === 'http://allowed-client.com');
  }
});

postMessage跨域

适用于iframe/window之间的通信:

// 发送方
window.parent.postMessage('message content', 'http://target-origin.com');

// 接收方
window.addEventListener('message', (event) => {
  if (event.origin !== 'http://trusted-origin.com') return;
  console.log('Received message:', event.data);
});

Nginx反向代理

通过Nginx配置实现请求转发:

server {
    listen 80;
    server_name localhost;

    location /api/ {
        proxy_pass http://backend-server/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

跨域资源共享的实际应用

处理复杂CORS场景

// Express中间件
const corsOptions = {
  origin: (origin, callback) => {
    const allowedOrigins = ['https://domain1.com', 'https://domain2.com'];
    if (!origin || allowedOrigins.includes(origin)) {
      callback(null, true);
    } else {
      callback(new Error('Not allowed by CORS'));
    }
  },
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  exposedHeaders: ['X-Custom-Header'],
  credentials: true,
  maxAge: 86400
};

app.use(cors(corsOptions));

处理预检请求缓存

app.options('*', cors(corsOptions)); // 全局预检请求处理

安全注意事项

  1. 严格限制Access-Control-Allow-Origin,避免使用*
  2. 对敏感操作实施CSRF防护
  3. 验证所有跨域请求的Origin头
  4. 限制允许的HTTP方法和头信息
// 安全示例
app.use((req, res, next) => {
  const allowedOrigins = new Set([
    'https://www.myapp.com',
    'https://api.myapp.com'
  ]);
  
  const origin = req.headers.origin;
  if (allowedOrigins.has(origin)) {
    res.setHeader('Access-Control-Allow-Origin', origin);
    res.setHeader('Vary', 'Origin');
  }
  
  // 其他安全头
  res.setHeader('X-Content-Type-Options', 'nosniff');
  next();
});

性能优化策略

  1. 预检请求缓存:设置Access-Control-Max-Age
  2. 减少不必要的预检请求:尽量使用简单请求
  3. CDN加速跨域资源
  4. 压缩跨域响应数据
// 设置预检请求缓存
app.use((req, res, next) => {
  res.setHeader('Access-Control-Max-Age', '600');
  next();
});

常见问题排查

  1. 检查响应头是否正确设置
  2. 确认请求是否满足简单请求条件
  3. 验证服务器是否正确处理OPTIONS方法
  4. 检查浏览器控制台错误信息
  5. 使用curl测试API响应头
# 使用curl测试
curl -I -X OPTIONS http://api.example.com/resource

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:RESTful API设计

下一篇:负载均衡策略

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌