跨域

跨域问题详解

总体来说两点:

  1. cors
  2. nginx 配置域名映射

什么是跨域问题

跨域问题是浏览器的安全机制(同源策略),当网页从一个域名向另一个域名发送请求时,浏览器会阻止这种请求。

同源策略判断标准

浏览器检查三个要素:协议 + 域名 + 端口

javascript 复制代码
// 当前页面:https://admin.company.com:443

// ✅ 同源请求
'https://admin.company.com:443/api/data'
'https://admin.company.com/other-page'

// ❌ 跨域请求  
'http://admin.company.com/api'          // 协议不同
'https://api.company.com/data'          // 域名不同
'https://admin.company.com:8080/api'    // 端口不同

为什么要限制跨域

1. 保护用户隐私

javascript 复制代码
// 恶意网站 evil.com 的页面
// 如果没有跨域限制,可以:
fetch('https://bank.com/account/balance')  // 窃取银行信息
fetch('https://social.com/api/messages')   // 窃取私人消息

2. 防止 CSRF 攻击

javascript 复制代码
// 利用用户登录状态执行恶意操作
fetch('https://bank.com/transfer', {
  method: 'POST',
  credentials: 'include',
  body: JSON.stringify({
    to: 'hacker-account',
    amount: 10000
  })
});

3. 防止信息泄露

javascript 复制代码
// 探测内网信息
fetch('http://192.168.1.100:8080/admin/users')
  .then(() => console.log('发现内网服务!'))

跨域问题的表现

浏览器报错信息

csharp 复制代码
Access to fetch at 'http://api.example.com/data' 
from origin 'https://web.example.com' 
has been blocked by CORS policy: 
No 'Access-Control-Allow-Origin' header is present on the requested resource.

前端代码失败

javascript 复制代码
fetch('http://api.example.com/data')
  .then(response => response.json())
  .catch(error => {
    console.error('跨域请求被阻止!', error);
    // 功能无法正常使用
  });

重要概念澄清

跨域只存在于浏览器环境

javascript 复制代码
// ❌ 有跨域问题:浏览器中的网页请求
fetch('https://api.other-domain.com/data')

// ✅ 没有跨域问题:服务器端调用
// Java后端调用其他服务
restTemplate.getForObject("https://api.other-domain.com/data", String.class);

跨域是前端问题,不是后端问题

  • 后端服务之间的调用不受跨域限制
  • 只有浏览器中的JavaScript请求才会被跨域策略阻止

跨域解决方案

1. CORS 配置(最常用)

后端设置响应头
java 复制代码
// Java Spring 示例
@CrossOrigin(origins = "https://web.company.com")
@RestController
public class ApiController {
    @GetMapping("/data")
    public ResponseEntity<String> getData() {
        return ResponseEntity.ok("success");
    }
}
全局 CORS 配置
java 复制代码
@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("https://web.company.com")
                .allowedMethods("GET", "POST", "PUT", "DELETE")
                .allowedHeaders("*")
                .allowCredentials(true)
                .maxAge(3600);
    }
}

2. 域名映射/反向代理(推荐)

Nginx 配置
nginx 复制代码
server {
    listen 80;
    server_name web.company.com;
    
    # 前端页面
    location / {
        proxy_pass http://frontend-server;
    }
    
    # API请求代理到后端
    location /api/ {
        proxy_pass http://backend-server/;
        proxy_set_header Host $proxy_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
效果
javascript 复制代码
// 前端代码改为同域请求
fetch('/api/data')  // 浏览器认为是同域,不会跨域

3. 前端代理(开发环境)

Webpack 配置
javascript 复制代码
// webpack.config.js
module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'http://backend-server.com',
        changeOrigin: true,
        pathRewrite: {
          '^/api': ''
        }
      }
    }
  }
};

4. 后端代理

java 复制代码
// 在前端同域的后端添加代理接口
@RestController
public class ProxyController {
    
    @Autowired
    private RestTemplate restTemplate;
    
    @GetMapping("/api/proxy/data")
    public ResponseEntity<String> proxyData() {
        // 后端调用其他服务,没有跨域问题
        String result = restTemplate.getForObject(
            "http://other-service.com/data", 
            String.class
        );
        return ResponseEntity.ok(result);
    }
}

实际应用建议

生产环境推荐做法

  1. 统一域名:通过反向代理让前后端在同一域名下
  2. CORS配置:如果必须跨域,在后端配置允许的源

开发环境常见做法

arduino 复制代码
前端开发服务器:http://localhost:3000
后端开发服务器:http://localhost:8080
通过前端代理解决跨域

企业级部署

bash 复制代码
用户访问:https://app.company.com
页面请求:https://app.company.com/dashboard     → 前端
API请求: https://app.company.com/api/users     → 后端

# 通过 Nginx 反向代理实现统一域名

总结

  • 🔒 跨域是浏览器安全机制,保护用户免受恶意攻击
  • 🌐 只影响浏览器中的请求,服务器间调用不受限制
  • 🛠️ 主流解决方案:域名映射/反向代理 + CORS配置
  • 最佳实践:前后端保持同域名,通过代理实现
  • 🚫 避免:完全关闭跨域限制,会带来安全风险

跨域问题虽然常见,但有成熟的解决方案。选择合适的方案可以在保证安全的前提下,提供良好的用户体验。

相关推荐
Olrookie1 小时前
若依前后端分离版学习笔记(三)——表结构介绍
笔记·后端·mysql
沸腾_罗强1 小时前
Bugs
后端
一条GO1 小时前
ORM中实现SaaS的数据与库的隔离
后端
京茶吉鹿1 小时前
"if else" 堆成山?这招让你的代码优雅起飞!
java·后端
长安不见1 小时前
从 NPE 到高内聚:Spring 构造器注入的真正价值
后端
你我约定有三1 小时前
RabbitMQ--消息丢失问题及解决
java·开发语言·分布式·后端·rabbitmq·ruby
程序视点2 小时前
望言OCR 2025终极评测:免费版VS专业版全方位对比(含免费下载)
前端·后端·github
rannn_1112 小时前
Java学习|黑马笔记|Day23】网络编程、反射、动态代理
java·笔记·后端·学习
一杯科技拿铁2 小时前
Go 的时间包:理解单调时间与挂钟时间
开发语言·后端·golang
独泪了无痕2 小时前
Hutool之CollStreamUtil:集合流操作的神器
后端