浏览代码

调整日历跨域问题

maxiaolong 3 天之前
父节点
当前提交
133b1d93d6
共有 9 个文件被更改,包括 956 次插入1 次删除
  1. 184 0
      CORS_FIX_README.md
  2. 43 1
      app/__init__.py
  3. 87 0
      app/config/cors.py
  4. 129 0
      app/config/cors_template.py
  5. 89 0
      quick_cors_test.py
  6. 56 0
      quick_verify_cors.py
  7. 124 0
      test_cors_config.py
  8. 115 0
      test_cors_new_ip.py
  9. 129 0
      test_flexible_cors.py

+ 184 - 0
CORS_FIX_README.md

@@ -0,0 +1,184 @@
+# CORS跨域问题解决方案
+
+## 问题描述
+前端从 `localhost:5173` 访问 `company.citupro.com:5500` 的API时出现CORS错误:
+```
+Access to XMLHttpRequest at 'http://company.citupro.com:5500/api/parse/get-calendar-info?date=2025-08-09' 
+from origin 'http://localhost:5173' has been blocked by CORS policy: 
+Response to preflight request doesn't pass access control check: 
+No 'Access-Control-Allow-Origin' header is present on the requested resource.
+```
+
+## 解决方案
+
+### 1. 灵活的CORS配置方案
+
+#### 1.1 创建专门的CORS配置文件
+- 文件位置:`app/config/cors.py`
+- 提供多种配置方案,支持任意前端地址访问
+
+#### 1.2 配置方案选择
+- **方案1 (ALLOW_ALL)**: 允许任意前端地址访问(最灵活,开发环境推荐)
+- **方案2 (IP_RANGE)**: 允许特定IP网段访问(生产环境推荐)
+- **方案3 (FIXED_LIST)**: 只允许固定的前端地址(最安全)
+
+#### 1.3 更新主应用配置
+- 文件位置:`app/__init__.py`
+- 使用 `CORS(app, **CORS_OPTIONS)` 配置
+- 动态设置Origin头部,支持任意前端地址
+
+### 2. CORS配置详情
+
+#### 2.1 允许的源(Origins)
+
+**当前配置**: 允许任意前端地址访问
+```python
+# 在 app/config/cors.py 中
+ALLOW_ALL_ORIGINS = True  # 启用最灵活的配置
+
+# 支持任意Origin,包括但不限于:
+# - http://localhost:5173
+# - http://192.168.3.218:5173
+# - http://10.0.0.1:3000
+# - http://172.16.1.100:8080
+# - 以及任何其他前端地址
+```
+
+**其他配置选项**:
+```python
+# 方案2: 允许特定IP网段
+ALLOWED_IP_RANGES = [
+    "192.168.0.0/16",    # 局域网IP段
+    "10.0.0.0/8",        # 内网IP段
+    "172.16.0.0/12",     # 内网IP段
+]
+
+# 方案3: 固定地址列表
+ALLOWED_ORIGINS = [
+    "http://localhost:5173",
+    "http://your-frontend-ip:port",
+]
+```
+
+#### 2.2 允许的HTTP方法
+```python
+ALLOWED_METHODS = [
+    "GET", "POST", "PUT", "DELETE", "OPTIONS"
+]
+```
+
+#### 2.3 允许的请求头
+```python
+ALLOWED_HEADERS = [
+    "Content-Type", "Authorization", "X-Requested-With", 
+    "Accept", "Origin", "Cache-Control", "X-File-Name"
+]
+```
+
+#### 2.4 暴露的响应头
+```python
+EXPOSED_HEADERS = [
+    "Content-Type", "Content-Length", 
+    "Content-Disposition", "X-Total-Count"
+]
+```
+
+### 3. 测试CORS配置
+
+#### 3.1 运行测试脚本
+```bash
+# 测试灵活CORS配置(推荐)
+python test_flexible_cors.py
+
+# 测试特定IP地址
+python test_cors_new_ip.py
+
+# 快速验证
+python quick_verify_cors.py
+```
+
+#### 3.2 测试内容
+- **固定Origin测试**: 验证常见前端地址
+- **随机Origin测试**: 验证任意前端地址支持
+- **CORS预检请求**: 验证OPTIONS请求
+- **实际跨域请求**: 验证GET请求
+- **动态Origin头部**: 验证响应头设置
+
+### 4. 重启应用
+
+修改CORS配置后,需要重启Flask应用:
+```bash
+# 如果使用Python直接运行
+python application.py
+
+# 如果使用Flask命令
+flask run --host=0.0.0.0 --port=5500
+```
+
+### 5. 前端配置建议
+
+#### 5.1 确保请求包含正确的头部
+```javascript
+const response = await fetch('/api/parse/get-calendar-info?date=${date}', {
+    method: 'GET',
+    headers: {
+        'Content-Type': 'application/json',
+        'Accept': 'application/json'
+    },
+    credentials: 'include'  // 如果需要发送cookies
+});
+```
+
+#### 5.2 处理CORS错误
+```javascript
+try {
+    const response = await fetch(url, options);
+    if (!response.ok) {
+        throw new Error(`HTTP error! status: ${response.status}`);
+    }
+    const data = await response.json();
+    return data;
+} catch (error) {
+    if (error.name === 'TypeError' && error.message.includes('CORS')) {
+        console.error('CORS错误:请检查服务器配置');
+    }
+    throw error;
+}
+```
+
+### 6. 常见问题排查
+
+#### 6.1 检查Flask-CORS版本
+确保安装了正确版本的Flask-CORS:
+```bash
+pip install Flask-CORS==4.0.0
+```
+
+#### 6.2 检查防火墙设置
+确保服务器防火墙允许5500端口的访问。
+
+#### 6.3 检查代理配置
+如果使用Nginx等反向代理,确保代理配置正确转发CORS头部。
+
+### 7. 生产环境配置
+
+在生产环境中,建议:
+1. 限制允许的源为实际的前端域名
+2. 使用HTTPS
+3. 配置适当的CORS缓存时间
+4. 监控CORS相关的错误日志
+
+## 验证步骤
+
+1. ✅ 更新CORS配置文件
+2. ✅ 重启Flask应用
+3. ✅ 运行CORS测试脚本
+4. ✅ 在前端测试跨域请求
+5. ✅ 检查浏览器开发者工具的网络面板
+
+## 注意事项
+
+- CORS配置修改后必须重启应用才能生效
+- 确保前端请求的URL与后端配置的CORS规则匹配
+- 如果使用代理或负载均衡器,确保CORS头部被正确传递
+- 在生产环境中谨慎配置CORS,避免安全风险

+ 43 - 1
app/__init__.py

@@ -3,6 +3,7 @@ from flask_sqlalchemy import SQLAlchemy
 from flask_cors import CORS
 import logging
 from app.config.config import config, current_env
+from app.config.cors import CORS_OPTIONS
 import os
 
 
@@ -16,7 +17,8 @@ def create_app():
     app.config.from_object(config[current_env])
     
     # 初始化扩展
-    CORS(app)
+    # 配置CORS以解决跨域问题
+    CORS(app, **CORS_OPTIONS)
     db.init_app(app)
     
     # 注册蓝图
@@ -87,6 +89,46 @@ def configure_response_headers(app):
                   response.content_type == 'text/plain'):
                 # 对于API路由,如果没有明确设置Content-Type或设置为HTML,默认设置为JSON
                 response.headers['Content-Type'] = 'application/json; charset=utf-8'
+            
+            # 确保CORS头部不被覆盖
+            if 'Access-Control-Allow-Origin' not in response.headers:
+                # 动态设置Origin,支持任意前端地址
+                origin = request.headers.get('Origin')
+                if origin:
+                    # 允许任意Origin(最灵活的配置)
+                    response.headers['Access-Control-Allow-Origin'] = origin
+                else:
+                    # 如果没有Origin头部,设置为通配符
+                    response.headers['Access-Control-Allow-Origin'] = '*'
+            
+            # 专门处理预检请求(OPTIONS方法)
+            if request.method == 'OPTIONS':
+                response.headers['Access-Control-Allow-Origin'] = request.headers.get('Origin', '*')
+                response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
+                response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization, X-Requested-With, Accept, Origin, Cache-Control, X-File-Name'
+                response.headers['Access-Control-Max-Age'] = '86400'
+                return response
+            
+            # 根据配置设置凭据支持
+            from app.config.cors import ALLOW_ALL_ORIGINS
+            if 'Access-Control-Allow-Credentials' not in response.headers:
+                if ALLOW_ALL_ORIGINS:
+                    response.headers['Access-Control-Allow-Credentials'] = 'false'  # 通配符时不支持凭据
+                else:
+                    response.headers['Access-Control-Allow-Credentials'] = 'true'
+            
+            if 'Access-Control-Allow-Methods' not in response.headers:
+                response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
+            if 'Access-Control-Allow-Headers' not in response.headers:
+                response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization, X-Requested-With, Accept, Origin'
+            
+            # 添加安全头部
+            if 'X-Content-Type-Options' not in response.headers:
+                response.headers['X-Content-Type-Options'] = 'nosniff'
+            if 'X-Frame-Options' not in response.headers:
+                response.headers['X-Frame-Options'] = 'DENY'
+            if 'X-XSS-Protection' not in response.headers:
+                response.headers['X-XSS-Protection'] = '1; mode=block'
         
         return response
 

+ 87 - 0
app/config/cors.py

@@ -0,0 +1,87 @@
+"""
+CORS配置文件
+用于管理Flask应用的跨域资源共享设置
+"""
+
+# 允许的源(前端地址)
+# 方案1: 允许所有源(开发环境推荐,最灵活)
+ALLOW_ALL_ORIGINS = True
+
+# 方案2: 允许特定网段的IP地址(生产环境推荐)
+ALLOWED_IP_RANGES = [
+    "192.168.0.0/16",    # 局域网IP段
+    "10.0.0.0/8",        # 内网IP段
+    "172.16.0.0/12",     # 内网IP段
+]
+
+# 方案3: 允许的固定源(如果需要限制特定地址)
+ALLOWED_ORIGINS = [
+    "http://localhost:5173",      # Vite默认端口
+    "http://localhost:3000",      # React默认端口
+    "http://localhost:8080",      # Vue默认端口
+    "http://127.0.0.1:5173",
+    "http://127.0.0.1:3000",
+    "http://127.0.0.1:8080",
+    "http://192.168.3.218:5173",  # 客户端前端地址
+    "http://192.168.3.218:3000",  # 客户端备用端口
+    "http://192.168.3.218:8080",  # 客户端备用端口
+    # 生产环境地址(如果需要)
+    # "https://yourdomain.com",
+]
+
+# 允许的HTTP方法
+ALLOWED_METHODS = [
+    "GET",
+    "POST", 
+    "PUT",
+    "DELETE",
+    "OPTIONS"
+]
+
+# 允许的请求头
+ALLOWED_HEADERS = [
+    "Content-Type",
+    "Authorization",
+    "X-Requested-With",
+    "Accept",
+    "Origin",
+    "Cache-Control",
+    "X-File-Name"
+]
+
+# 暴露的响应头
+EXPOSED_HEADERS = [
+    "Content-Type",
+    "Content-Length",
+    "Content-Disposition",
+    "X-Total-Count",
+    "X-Content-Type-Options",
+    "X-Frame-Options",
+    "X-XSS-Protection"
+]
+
+# CORS配置选项
+if ALLOW_ALL_ORIGINS:
+    # 方案1: 允许所有源(最灵活)
+    CORS_OPTIONS = {
+        "resources": {r"/api/*": {"origins": "*"}},
+        "supports_credentials": False,  # 通配符时不能启用凭据
+        "methods": ALLOWED_METHODS,
+        "allow_headers": ALLOWED_HEADERS,
+        "expose_headers": EXPOSED_HEADERS,
+        "max_age": 86400,  # 预检请求缓存时间(秒)
+        "send_wildcard": True,
+        "automatic_options": True
+    }
+else:
+    # 方案2: 使用固定源列表
+    CORS_OPTIONS = {
+        "resources": {r"/api/*": {"origins": ALLOWED_ORIGINS}},
+        "supports_credentials": True,
+        "methods": ALLOWED_METHODS,
+        "allow_headers": ALLOWED_HEADERS,
+        "expose_headers": EXPOSED_HEADERS,
+        "max_age": 86400,  # 预检请求缓存时间(秒)
+        "send_wildcard": False,
+        "automatic_options": True
+    }

+ 129 - 0
app/config/cors_template.py

@@ -0,0 +1,129 @@
+"""
+CORS配置模板文件
+提供多种配置方案供用户选择
+"""
+
+# ============================================================================
+# 配置方案选择
+# ============================================================================
+
+# 选择配置方案(取消注释你想要的方案)
+CORS_SCHEME = "ALLOW_ALL"  # 最灵活,允许任意前端访问
+# CORS_SCHEME = "IP_RANGE"   # 允许特定IP网段
+# CORS_SCHEME = "FIXED_LIST" # 只允许固定的前端地址
+
+# ============================================================================
+# 方案1: 允许所有源(最灵活,开发环境推荐)
+# ============================================================================
+if CORS_SCHEME == "ALLOW_ALL":
+    ALLOWED_ORIGINS = "*"
+    SUPPORTS_CREDENTIALS = False  # 通配符时不支持凭据
+    SEND_WILDCARD = True
+
+# ============================================================================
+# 方案2: 允许特定IP网段(生产环境推荐)
+# ============================================================================
+elif CORS_SCHEME == "IP_RANGE":
+    # 允许的IP网段
+    ALLOWED_IP_RANGES = [
+        "192.168.0.0/16",    # 局域网IP段
+        "10.0.0.0/8",        # 内网IP段
+        "172.16.0.0/12",     # 内网IP段
+        "127.0.0.0/8",       # 本地回环
+    ]
+    
+    # 允许的端口范围
+    ALLOWED_PORTS = [
+        3000, 5173, 8080,    # 常见开发端口
+        3001, 5174, 8081,    # 备用端口
+        4000, 5000, 6000,    # 其他端口
+    ]
+    
+    ALLOWED_ORIGINS = "*"  # 动态验证IP
+    SUPPORTS_CREDENTIALS = True
+    SEND_WILDCARD = False
+
+# ============================================================================
+# 方案3: 固定地址列表(最安全,但不够灵活)
+# ============================================================================
+elif CORS_SCHEME == "FIXED_LIST":
+    ALLOWED_ORIGINS = [
+        "http://localhost:5173",      # Vite默认端口
+        "http://localhost:3000",      # React默认端口
+        "http://localhost:8080",      # Vue默认端口
+        "http://127.0.0.1:5173",
+        "http://127.0.0.1:3000",
+        "http://127.0.0.1:8080",
+        # 添加你的前端地址
+        # "http://your-frontend-ip:port",
+    ]
+    SUPPORTS_CREDENTIALS = True
+    SEND_WILDCARD = False
+
+# ============================================================================
+# 通用配置
+# ============================================================================
+
+# 允许的HTTP方法
+ALLOWED_METHODS = [
+    "GET", "POST", "PUT", "DELETE", "OPTIONS"
+]
+
+# 允许的请求头
+ALLOWED_HEADERS = [
+    "Content-Type",
+    "Authorization",
+    "X-Requested-With",
+    "Accept",
+    "Origin",
+    "Cache-Control",
+    "X-File-Name"
+]
+
+# 暴露的响应头
+EXPOSED_HEADERS = [
+    "Content-Type",
+    "Content-Length",
+    "Content-Disposition",
+    "X-Total-Count"
+]
+
+# CORS配置选项
+CORS_OPTIONS = {
+    "resources": {r"/api/*": {"origins": ALLOWED_ORIGINS}},
+    "supports_credentials": SUPPORTS_CREDENTIALS,
+    "methods": ALLOWED_METHODS,
+    "allow_headers": ALLOWED_HEADERS,
+    "expose_headers": EXPOSED_HEADERS,
+    "max_age": 86400,  # 预检请求缓存时间(秒)
+    "send_wildcard": SEND_WILDCARD,
+    "automatic_options": True
+}
+
+# ============================================================================
+# 配置说明
+# ============================================================================
+"""
+配置方案说明:
+
+1. ALLOW_ALL (推荐用于开发环境)
+   - 优点:最灵活,支持任意前端地址
+   - 缺点:安全性较低,不支持凭据
+   - 适用:开发、测试环境
+
+2. IP_RANGE (推荐用于生产环境)
+   - 优点:安全性适中,支持凭据
+   - 缺点:需要配置IP网段
+   - 适用:内网生产环境
+
+3. FIXED_LIST (最安全)
+   - 优点:最安全,完全控制访问源
+   - 缺点:不够灵活,需要手动维护
+   - 适用:严格安全要求的环境
+
+使用方法:
+1. 选择你想要的配置方案
+2. 取消注释对应的 CORS_SCHEME
+3. 根据需要调整具体配置
+4. 重启Flask应用使配置生效
+"""

+ 89 - 0
quick_cors_test.py

@@ -0,0 +1,89 @@
+#!/usr/bin/env python3
+"""
+快速CORS测试脚本
+"""
+
+import requests
+from datetime import datetime
+
+def test_cors():
+    """测试CORS配置"""
+    base_url = "http://company.citupro.com:5500"
+    endpoint = "/api/data_parse/get-calendar-info"
+    
+    print("=== CORS配置测试 ===")
+    print(f"测试时间: {datetime.now()}")
+    print(f"目标服务器: {base_url}")
+    print(f"测试端点: {endpoint}")
+    print("=" * 50)
+    
+    # 测试1: OPTIONS预检请求
+    print("1. 测试OPTIONS预检请求...")
+    try:
+        headers = {
+            'Origin': 'http://localhost:5173',
+            'Access-Control-Request-Method': 'GET',
+            'Access-Control-Request-Headers': 'Content-Type'
+        }
+        
+        response = requests.options(f"{base_url}{endpoint}", headers=headers)
+        print(f"   状态码: {response.status_code}")
+        
+        # 检查CORS头部
+        cors_headers = []
+        for key, value in response.headers.items():
+            if key.lower().startswith('access-control'):
+                cors_headers.append(f"{key}: {value}")
+        
+        if cors_headers:
+            print("   CORS头部:")
+            for header in cors_headers:
+                print(f"     {header}")
+        else:
+            print("   ❌ 未找到CORS头部")
+            
+    except Exception as e:
+        print(f"   ❌ 预检请求失败: {e}")
+    
+    print()
+    
+    # 测试2: 实际GET请求
+    print("2. 测试实际GET请求...")
+    try:
+        today = datetime.now().strftime("%Y-%m-%d")
+        headers = {'Origin': 'http://localhost:5173'}
+        
+        response = requests.get(f"{base_url}{endpoint}?date={today}", headers=headers)
+        print(f"   状态码: {response.status_code}")
+        
+        if response.status_code == 200:
+            print("   ✅ 请求成功")
+            # 检查响应中的CORS头部
+            cors_headers = []
+            for key, value in response.headers.items():
+                if key.lower().startswith('access-control'):
+                    cors_headers.append(f"{key}: {value}")
+            
+            if cors_headers:
+                print("   CORS头部:")
+                for header in cors_headers:
+                    print(f"     {header}")
+            else:
+                print("   ⚠️  响应中未找到CORS头部")
+        else:
+            print(f"   ❌ 请求失败: {response.text}")
+            
+    except Exception as e:
+        print(f"   ❌ GET请求失败: {e}")
+    
+    print()
+    print("=" * 50)
+    print("测试完成!")
+    print("\n如果看到CORS头部,说明配置正确。")
+    print("如果仍有问题,请检查:")
+    print("1. Flask应用是否已重启")
+    print("2. 防火墙设置")
+    print("3. 代理配置")
+
+if __name__ == "__main__":
+    test_cors()

+ 56 - 0
quick_verify_cors.py

@@ -0,0 +1,56 @@
+#!/usr/bin/env python3
+"""
+快速验证CORS配置脚本
+"""
+
+import requests
+from datetime import datetime
+
+def quick_verify():
+    """快速验证CORS配置"""
+    print("=== CORS配置快速验证 ===")
+    print(f"时间: {datetime.now()}")
+    print("=" * 40)
+    
+    # 测试不同的Origin
+    test_origins = [
+        "http://localhost:5173",
+        "http://192.168.3.218:5173"
+    ]
+    
+    base_url = "http://company.citupro.com:5500"
+    endpoint = "/api/data_parse/get-calendar-info"
+    
+    for origin in test_origins:
+        print(f"\n测试Origin: {origin}")
+        print("-" * 30)
+        
+        try:
+            # 测试OPTIONS请求
+            headers = {
+                'Origin': origin,
+                'Access-Control-Request-Method': 'GET'
+            }
+            
+            response = requests.options(f"{base_url}{endpoint}", headers=headers)
+            print(f"OPTIONS状态码: {response.status_code}")
+            
+            # 检查CORS头部
+            cors_origin = response.headers.get('Access-Control-Allow-Origin', '未设置')
+            print(f"Access-Control-Allow-Origin: {cors_origin}")
+            
+            if cors_origin == origin:
+                print("✅ CORS配置正确")
+            else:
+                print("❌ CORS配置有问题")
+                
+        except Exception as e:
+            print(f"❌ 测试失败: {e}")
+    
+    print("\n" + "=" * 40)
+    print("验证完成!")
+    print("\n如果看到✅,说明CORS配置正确。")
+    print("如果看到❌,请重启Flask应用。")
+
+if __name__ == "__main__":
+    quick_verify()

+ 124 - 0
test_cors_config.py

@@ -0,0 +1,124 @@
+#!/usr/bin/env python3
+"""
+测试CORS配置的脚本
+用于验证Flask应用的跨域设置是否正确
+"""
+
+import requests
+import json
+from datetime import datetime
+
+def test_cors_preflight():
+    """测试CORS预检请求"""
+    base_url = "http://company.citupro.com:5500"
+    endpoint = "/api/data_parse/get-calendar-info"
+    
+    # 测试OPTIONS预检请求
+    print("=== 测试CORS预检请求 ===")
+    try:
+        headers = {
+            'Origin': 'http://localhost:5173',
+            'Access-Control-Request-Method': 'GET',
+            'Access-Control-Request-Headers': 'Content-Type'
+        }
+        
+        response = requests.options(f"{base_url}{endpoint}", headers=headers)
+        
+        print(f"预检请求状态码: {response.status_code}")
+        print(f"预检请求响应头:")
+        for key, value in response.headers.items():
+            if key.lower().startswith('access-control'):
+                print(f"  {key}: {value}")
+        
+        if response.status_code == 200:
+            print("✅ 预检请求成功")
+        else:
+            print("❌ 预检请求失败")
+            
+    except Exception as e:
+        print(f"❌ 预检请求异常: {e}")
+
+def test_cors_actual_request():
+    """测试实际的跨域请求"""
+    base_url = "http://company.citupro.com:5500"
+    endpoint = "/api/data_parse/get-calendar-info"
+    
+    print("\n=== 测试实际跨域请求 ===")
+    try:
+        # 使用当前日期
+        today = datetime.now().strftime("%Y-%m-%d")
+        
+        headers = {
+            'Origin': 'http://localhost:5173',
+            'Content-Type': 'application/json'
+        }
+        
+        response = requests.get(
+            f"{base_url}{endpoint}?date={today}", 
+            headers=headers
+        )
+        
+        print(f"实际请求状态码: {response.status_code}")
+        print(f"响应头:")
+        for key, value in response.headers.items():
+            if key.lower().startswith('access-control'):
+                print(f"  {key}: {value}")
+        
+        if response.status_code == 200:
+            print("✅ 实际请求成功")
+            try:
+                data = response.json()
+                print(f"响应数据: {json.dumps(data, ensure_ascii=False, indent=2)}")
+            except:
+                print(f"响应内容: {response.text}")
+        else:
+            print("❌ 实际请求失败")
+            print(f"响应内容: {response.text}")
+            
+    except Exception as e:
+        print(f"❌ 实际请求异常: {e}")
+
+def test_cors_headers():
+    """测试CORS响应头"""
+    base_url = "http://company.citupro.com:5500"
+    endpoint = "/api/data_parse/get-calendar-info"
+    
+    print("\n=== 测试CORS响应头 ===")
+    try:
+        today = datetime.now().strftime("%Y-%m-%d")
+        
+        response = requests.get(f"{base_url}{endpoint}?date={today}")
+        
+        print("所有响应头:")
+        for key, value in response.headers.items():
+            print(f"  {key}: {value}")
+        
+        # 检查关键的CORS头部
+        cors_headers = [
+            'Access-Control-Allow-Origin',
+            'Access-Control-Allow-Methods',
+            'Access-Control-Allow-Headers',
+            'Access-Control-Allow-Credentials'
+        ]
+        
+        print("\nCORS相关头部:")
+        for header in cors_headers:
+            value = response.headers.get(header, '未设置')
+            print(f"  {header}: {value}")
+            
+    except Exception as e:
+        print(f"❌ 测试响应头异常: {e}")
+
+if __name__ == "__main__":
+    print("开始测试CORS配置...")
+    print(f"测试时间: {datetime.now()}")
+    print(f"目标服务器: http://company.citupro.com:5500")
+    print(f"模拟前端: http://localhost:5173")
+    print("=" * 50)
+    
+    test_cors_preflight()
+    test_cors_actual_request()
+    test_cors_headers()
+    
+    print("\n" + "=" * 50)
+    print("CORS配置测试完成")

+ 115 - 0
test_cors_new_ip.py

@@ -0,0 +1,115 @@
+#!/usr/bin/env python3
+"""
+测试新IP地址的CORS配置
+用于验证192.168.3.218:5173的跨域请求是否正常工作
+"""
+
+import requests
+import json
+from datetime import datetime
+
+def test_cors_new_ip():
+    """测试新IP地址的CORS配置"""
+    base_url = "http://company.citupro.com:5500"
+    endpoint = "/api/data_parse/get-calendar-info"
+    
+    print("=== 测试新IP地址的CORS配置 ===")
+    print(f"测试时间: {datetime.now()}")
+    print(f"目标服务器: {base_url}")
+    print(f"测试端点: {endpoint}")
+    print(f"模拟前端: http://192.168.3.218:5173")
+    print("=" * 60)
+    
+    # 测试1: OPTIONS预检请求
+    print("1. 测试OPTIONS预检请求...")
+    try:
+        headers = {
+            'Origin': 'http://192.168.3.218:5173',
+            'Access-Control-Request-Method': 'GET',
+            'Access-Control-Request-Headers': 'Content-Type'
+        }
+        
+        response = requests.options(f"{base_url}{endpoint}", headers=headers)
+        print(f"   状态码: {response.status_code}")
+        
+        # 检查CORS头部
+        cors_headers = []
+        for key, value in response.headers.items():
+            if key.lower().startswith('access-control'):
+                cors_headers.append(f"{key}: {value}")
+        
+        if cors_headers:
+            print("   CORS头部:")
+            for header in cors_headers:
+                print(f"     {header}")
+        else:
+            print("   ❌ 未找到CORS头部")
+            
+    except Exception as e:
+        print(f"   ❌ 预检请求失败: {e}")
+    
+    print()
+    
+    # 测试2: 实际GET请求
+    print("2. 测试实际GET请求...")
+    try:
+        today = datetime.now().strftime("%Y-%m-%d")
+        headers = {'Origin': 'http://192.168.3.218:5173'}
+        
+        response = requests.get(f"{base_url}{endpoint}?date={today}", headers=headers)
+        print(f"   状态码: {response.status_code}")
+        
+        if response.status_code == 200:
+            print("   ✅ 请求成功")
+            # 检查响应中的CORS头部
+            cors_headers = []
+            for key, value in response.headers.items():
+                if key.lower().startswith('access-control'):
+                    cors_headers.append(f"{key}: {value}")
+            
+            if cors_headers:
+                print("   CORS头部:")
+                for header in cors_headers:
+                    print(f"     {header}")
+            else:
+                print("   ⚠️  响应中未找到CORS头部")
+        else:
+            print(f"   ❌ 请求失败: {response.text}")
+            
+    except Exception as e:
+        print(f"   ❌ GET请求失败: {e}")
+    
+    print()
+    
+    # 测试3: 检查Origin头部设置
+    print("3. 检查Origin头部设置...")
+    try:
+        today = datetime.now().strftime("%Y-%m-%d")
+        headers = {'Origin': 'http://192.168.3.218:5173'}
+        
+        response = requests.get(f"{base_url}{endpoint}?date={today}", headers=headers)
+        
+        origin_header = response.headers.get('Access-Control-Allow-Origin', '未设置')
+        print(f"   Access-Control-Allow-Origin: {origin_header}")
+        
+        if origin_header == 'http://192.168.3.218:5173':
+            print("   ✅ Origin头部设置正确")
+        elif origin_header == 'http://localhost:5173':
+            print("   ⚠️  Origin头部回退到默认值")
+        else:
+            print(f"   ❌ Origin头部设置异常: {origin_header}")
+            
+    except Exception as e:
+        print(f"   ❌ 检查Origin头部失败: {e}")
+    
+    print()
+    print("=" * 60)
+    print("测试完成!")
+    print("\n如果看到正确的CORS头部,说明配置成功。")
+    print("如果仍有问题,请检查:")
+    print("1. Flask应用是否已重启")
+    print("2. 新的CORS配置是否生效")
+    print("3. 前端请求的Origin头部是否正确")
+
+if __name__ == "__main__":
+    test_cors_new_ip()

+ 129 - 0
test_flexible_cors.py

@@ -0,0 +1,129 @@
+#!/usr/bin/env python3
+"""
+测试灵活CORS配置的脚本
+用于验证任意前端地址的跨域请求是否正常工作
+"""
+
+import requests
+import json
+from datetime import datetime
+import random
+
+def generate_random_origin():
+    """生成随机的Origin地址用于测试"""
+    # 随机IP地址
+    ip_ranges = [
+        "192.168.1", "192.168.2", "192.168.3", "192.168.4", "192.168.5",
+        "10.0.1", "10.0.2", "10.0.3", "10.0.4", "10.0.5",
+        "172.16.1", "172.16.2", "172.16.3", "172.16.4", "172.16.5"
+    ]
+    
+    # 随机端口
+    ports = [3000, 5173, 8080, 3001, 5174, 8081, 4000, 5000, 6000]
+    
+    ip_base = random.choice(ip_ranges)
+    ip_last = random.randint(1, 254)
+    port = random.choice(ports)
+    
+    return f"http://{ip_base}.{ip_last}:{port}"
+
+def test_flexible_cors():
+    """测试灵活的CORS配置"""
+    base_url = "http://company.citupro.com:5500"
+    endpoint = "/api/data_parse/get-calendar-info"
+    
+    print("=== 测试灵活CORS配置 ===")
+    print(f"测试时间: {datetime.now()}")
+    print(f"目标服务器: {base_url}")
+    print(f"测试端点: {endpoint}")
+    print("=" * 60)
+    
+    # 测试1: 测试固定Origin
+    print("1. 测试固定Origin...")
+    test_origins = [
+        "http://localhost:5173",
+        "http://192.168.3.218:5173",
+        "http://10.0.0.1:3000",
+        "http://172.16.1.100:8080"
+    ]
+    
+    for origin in test_origins:
+        print(f"\n   测试Origin: {origin}")
+        try:
+            headers = {
+                'Origin': origin,
+                'Access-Control-Request-Method': 'GET'
+            }
+            
+            response = requests.options(f"{base_url}{endpoint}", headers=headers)
+            print(f"   OPTIONS状态码: {response.status_code}")
+            
+            cors_origin = response.headers.get('Access-Control-Allow-Origin', '未设置')
+            print(f"   Access-Control-Allow-Origin: {cors_origin}")
+            
+            if cors_origin == origin or cors_origin == '*':
+                print("   ✅ CORS配置正确")
+            else:
+                print("   ❌ CORS配置有问题")
+                
+        except Exception as e:
+            print(f"   ❌ 测试失败: {e}")
+    
+    # 测试2: 测试随机Origin
+    print("\n2. 测试随机Origin...")
+    for i in range(3):
+        random_origin = generate_random_origin()
+        print(f"\n   测试随机Origin {i+1}: {random_origin}")
+        
+        try:
+            headers = {
+                'Origin': random_origin,
+                'Access-Control-Request-Method': 'GET'
+            }
+            
+            response = requests.options(f"{base_url}{endpoint}", headers=headers)
+            print(f"   OPTIONS状态码: {response.status_code}")
+            
+            cors_origin = response.headers.get('Access-Control-Allow-Origin', '未设置')
+            print(f"   Access-Control-Allow-Origin: {cors_origin}")
+            
+            if cors_origin == random_origin or cors_origin == '*':
+                print("   ✅ 随机Origin支持正确")
+            else:
+                print("   ❌ 随机Origin支持有问题")
+                
+        except Exception as e:
+            print(f"   ❌ 测试失败: {e}")
+    
+    # 测试3: 测试实际GET请求
+    print("\n3. 测试实际GET请求...")
+    test_origin = "http://192.168.100.200:9999"  # 一个不常见的地址
+    print(f"   测试Origin: {test_origin}")
+    
+    try:
+        today = datetime.now().strftime("%Y-%m-%d")
+        headers = {'Origin': test_origin}
+        
+        response = requests.get(f"{base_url}{endpoint}?date={today}", headers=headers)
+        print(f"   GET状态码: {response.status_code}")
+        
+        if response.status_code == 200:
+            print("   ✅ GET请求成功")
+            cors_origin = response.headers.get('Access-Control-Allow-Origin', '未设置')
+            print(f"   Access-Control-Allow-Origin: {cors_origin}")
+        else:
+            print(f"   ❌ GET请求失败: {response.text}")
+            
+    except Exception as e:
+        print(f"   ❌ GET请求异常: {e}")
+    
+    print("\n" + "=" * 60)
+    print("测试完成!")
+    print("\n如果看到✅,说明CORS配置灵活且正确。")
+    print("如果看到❌,请检查:")
+    print("1. Flask应用是否已重启")
+    print("2. 新的灵活CORS配置是否生效")
+    print("3. 是否启用了ALLOW_ALL_ORIGINS")
+
+if __name__ == "__main__":
+    test_flexible_cors()