跨域

跨域问题详解

总体来说两点:

  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配置
  • 最佳实践:前后端保持同域名,通过代理实现
  • 🚫 避免:完全关闭跨域限制,会带来安全风险

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

相关推荐
uzong3 小时前
技术故障复盘模版
后端
GetcharZp3 小时前
基于 Dify + 通义千问的多模态大模型 搭建发票识别 Agent
后端·llm·agent
桦说编程4 小时前
Java 中如何创建不可变类型
java·后端·函数式编程
IT毕设实战小研4 小时前
基于Spring Boot 4s店车辆管理系统 租车管理系统 停车位管理系统 智慧车辆管理系统
java·开发语言·spring boot·后端·spring·毕业设计·课程设计
wyiyiyi4 小时前
【Web后端】Django、flask及其场景——以构建系统原型为例
前端·数据库·后端·python·django·flask
阿华的代码王国5 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
Jimmy5 小时前
AI 代理是什么,其有助于我们实现更智能编程
前端·后端·ai编程
AntBlack6 小时前
不当韭菜V1.1 :增强能力 ,辅助构建自己的交易规则
后端·python·pyqt
bobz9657 小时前
pip install 已经不再安全
后端
寻月隐君7 小时前
硬核实战:从零到一,用 Rust 和 Axum 构建高性能聊天服务后端
后端·rust·github