# 🚀 ERP 系统服务启动和 CORS 配置文档 ## 📋 系统组件概览 | 服务 | 端口 | 框架 | 状态 | |------|------|------|------| | 后端 API | 2011 | ASP.NET Core 6.0 | ✅ | | 前端管理 | 3001 | Vue 3 + Vite | ✅ | | 收银台 | 8888 | Python HTTP Server | ✅ | --- ## 🎯 快速启动 ### 一键启动脚本(Mac/Linux) ```bash #!/bin/bash # 创建脚本文件: start-all.sh cat > start-all.sh << 'SCRIPT' #!/bin/bash # 启动后端 (2011) echo "启动后端 API..." cd netcore dotnet run --urls="http://localhost:2011" --project src/Application/NCC.API & BACKEND_PID=$! # 等待后端启动 sleep 10 # 启动前端 (3001) echo "启动前端..." cd ../antis-ncc-admin npm run dev -- --port 3001 & FRONTEND_PID=$! echo "" echo "✅ 后端 API: http://localhost:2011" echo "✅ 前端管理: http://localhost:3001" echo "✅ 收银台: http://localhost:8888" echo "" echo "后端 PID: $BACKEND_PID" echo "前端 PID: $FRONTEND_PID" echo "" echo "停止服务: kill $BACKEND_PID $FRONTEND_PID" SCRIPT chmod +x start-all.sh ``` ### 分别启动 #### 后端启动 (2011) ```bash cd /Users/hexiaodong/Desktop/git/erp2025/Antis.Erp.Plat/netcore dotnet run --urls="http://localhost:2011" --project src/Application/NCC.API ``` #### 前端启动 (3001) ```bash cd /Users/hexiaodong/Desktop/git/erp2025/Antis.Erp.Plat/antis-ncc-admin npm run dev -- --port 3001 ``` #### 收银台启动 (8888) ```bash cd /Users/hexiaodong/Desktop/git/erp2025/Antis.Erp.Plat/sy python3 -m http.server 8888 ``` --- ## 🔒 CORS 配置详解 ### 后端 CORS 配置 **文件路径**: `netcore/src/Application/NCC.API/appsettings.json` ```json { "CorsAccessorSettings": { "PolicyName": "NCCCorsAccessor", "WithOrigins": [ "http://192.168.0.138:8080", "http://localhost:8080", "http://localhost:3021", "http://localhost:3014", "http://localhost:3015", "http://localhost:2011", "http://localhost:3009", "http://localhost:2016", "http://localhost:3000", "http://localhost:9528", "http://localhost:8200", "http://localhost:3001", // ← 前端访问源 "http://localhost:8080" ], "WithExposedHeaders": [ "access-token", "x-access-token", "Content-Disposition" ] } } ``` ### CORS 中间件配置 **文件路径**: `netcore/src/Application/NCC.API.Core/Startup.cs` #### ConfigureServices 方法 ```csharp public void ConfigureServices(IServiceCollection services) { // ... 其他配置 ... // 第 54 行:添加 CORS 服务 services.AddCorsAccessor(); // ... 其他配置 ... } ``` #### Configure 方法 ```csharp public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ...) { // ... 其他中间件 ... app.UseRouting(); // 第 197 行:应用 CORS 中间件 app.UseCorsAccessor(); // 第 199 行:JWT 认证 app.UseAuthentication(); // 第 200 行:授权检查 app.UseAuthorization(); // ... 其他中间件 ... app.UseEndpoints(endpoints => { /* ... */ }); } ``` ### CORS 配置类 **文件路径**: `netcore/src/Infrastructure/NCC/CorsAccessor/Options/CorsAccessorSettingsOptions.cs` ```csharp public sealed class CorsAccessorSettingsOptions : IConfigurableOptions { /// /// 策略名称 /// public string PolicyName { get; set; } /// /// 允许来源域名,没有配置则允许所有来源 /// public string[] WithOrigins { get; set; } /// /// 请求表头,没有配置则允许所有表头 /// public string[] WithHeaders { get; set; } /// /// 响应标头 /// public string[] WithExposedHeaders { get; set; } /// /// 设置跨域允许请求谓词,没有配置则允许所有 /// public string[] WithMethods { get; set; } /// /// 跨域请求中的凭据 /// public bool? AllowCredentials { get; set; } /// /// 设置预检过期时间 /// public int? SetPreflightMaxAge { get; set; } } ``` --- ## 🌐 跨域请求流程 ### 简单请求流程(GET 等) ``` 前端 (3001) ↓ Origin: http://localhost:3001 ↓ 后端 (2011) ↓ 检查 Origin 在 WithOrigins 中 ↓ 返回 Access-Control-Allow-Origin: http://localhost:3001 ↓ 浏览器允许前端接收响应 ✓ ``` ### 复杂请求流程(POST/PUT/DELETE + 自定义头) ``` 前端 (3001) ↓ 发起 POST 请求 ↓ 浏览器自动发送 OPTIONS 预检请求 ├─ Origin: http://localhost:3001 ├─ Access-Control-Request-Method: POST └─ Access-Control-Request-Headers: content-type ↓ 后端 (2011) CORS 中间件处理 ├─ 检查 Origin 在白名单中 ✓ ├─ 检查方法被允许 ✓ ├─ 检查头被允许 ✓ ↓ 返回预检响应 ├─ Access-Control-Allow-Origin: http://localhost:3001 ├─ Access-Control-Allow-Methods: POST, PUT, DELETE, ... ├─ Access-Control-Allow-Headers: content-type, ... └─ Access-Control-Allow-Credentials: true ↓ 浏览器预检通过 ✓ ↓ 浏览器发送真实 POST 请求 ↓ 后端处理并返回数据 ✓ ↓ 前端接收数据 ✓ ``` --- ## 🔧 API 端点验证 ### 测试后端连接 ```bash # 基本连接测试 curl -I http://localhost:2011 # 预期响应: HTTP 200 # API 文档 curl http://localhost:2011/antis.doc ``` ### 测试 CORS 预检请求 ```bash curl -X OPTIONS http://localhost:2011/api/some-endpoint \ -H "Origin: http://localhost:3001" \ -H "Access-Control-Request-Method: POST" \ -H "Access-Control-Request-Headers: content-type" \ -v ``` 预期响应头: ``` Access-Control-Allow-Origin: http://localhost:3001 Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS Access-Control-Allow-Headers: content-type Access-Control-Allow-Credentials: true ``` ### 前端 API 调用示例 ```javascript // axios 配置 import axios from 'axios' const request = axios.create({ baseURL: 'http://localhost:2011', timeout: 10000, withCredentials: true // 允许跨域凭据 }) // 请求拦截器 request.interceptors.request.use( config => { config.headers['Authorization'] = `Bearer ${token}` return config } ) // 调用 API request.get('/api/some-endpoint') .then(res => console.log(res)) .catch(err => console.error(err)) ``` --- ## ⚠️ 常见 CORS 错误排查 ### 错误 1:Access to XMLHttpRequest blocked by CORS policy **原因**: Origin 不在白名单中 **解决方案**: ```json // 在 appsettings.json 中添加 "WithOrigins": [ "http://localhost:3001" // ← 确保包含您的前端地址 ] ``` ### 错误 2:The value of the 'Access-Control-Allow-Credentials' header **原因**: AllowCredentials 为 true,但 AllowAnyOrigin 被设置 **解决方案**: ```csharp // 不能同时设置 builder.AllowAnyOrigin().AllowCredentials(); // ❌ 错误 // 应该明确指定来源 builder.WithOrigins("http://localhost:3001").AllowCredentials(); // ✅ 正确 ``` ### 错误 3:Response header 'access-token' is not allowed **原因**: 响应头未在白名单中 **解决方案**: ```json "WithExposedHeaders": [ "access-token", "x-access-token", "Content-Disposition" ] ``` --- ## 📊 CORS 配置清单 - [x] CORS 中间件在 ConfigureServices 中注册 - [x] CORS 中间件在 Configure 中应用 - [x] 前端源 (http://localhost:3001) 在白名单中 - [x] 允许 OPTIONS 请求 - [x] 允许所有 HTTP 方法 - [x] 允许自定义请求头 - [x] 暴露必要的响应头 - [x] 允许认证凭据 (Credentials) - [x] 预检请求正确处理 --- ## 🔐 安全建议 ### 生产环境配置 ```json { "CorsAccessorSettings": { "PolicyName": "ProductionCors", "WithOrigins": [ "https://yourdomain.com", // 只允许生产环境域名 "https://admin.yourdomain.com" ], "AllowCredentials": true, "SetPreflightMaxAge": 3600 } } ``` ### JWT 令牌管理 ```json { "JWTSettings": { "ValidateIssuerSigningKey": true, "IssuerSigningKey": "your-secure-key", "ValidateIssuer": true, "ValidIssuer": "your-issuer", "ValidateAudience": true, "ValidAudience": "your-audience", "ValidateLifetime": true, "ExpiredTime": 1440, "ClockSkew": 5 } } ``` --- ## 📞 故障诊断 ### 步骤 1: 检查服务状态 ```bash # 检查后端 curl -I http://localhost:2011 # 期望: HTTP 200 # 检查前端 curl -I http://localhost:3001 # 期望: HTTP 200 ``` ### 步骤 2: 查看浏览器控制台 1. 打开 F12 开发者工具 2. 切换到 **Network** 标签 3. 刷新页面 4. 查找 **OPTIONS** 请求(预检请求) 5. 检查 **Response Headers**: - `Access-Control-Allow-Origin` - `Access-Control-Allow-Methods` - `Access-Control-Allow-Headers` ### 步骤 3: 查看后端日志 ```bash # netcore 会在控制台输出 # 【时间】... # 【等级】... # 【消息】... # 查找与 CORS 相关的错误 ``` ### 步骤 4: 使用 curl 测试 ```bash # 模拟前端发送的预检请求 curl -X OPTIONS http://localhost:2011/api/endpoint \ -H "Origin: http://localhost:3001" \ -H "Access-Control-Request-Method: POST" \ -v # 检查响应头中是否包含 Access-Control-* 字段 ``` --- ## 🎯 总结 ✅ **配置文件**: `netcore/src/Application/NCC.API/appsettings.json` ✅ **中间件文件**: `netcore/src/Application/NCC.API.Core/Startup.cs` ✅ **CORS 策略**: `NCCCorsAccessor` ✅ **前端源**: `http://localhost:3001` ✓ (已在白名单中) ✅ **API 端口**: `2011` ✅ **跨域状态**: 已配置 ✓ --- **最后更新**: 2025-01-01 **维护者**: ERP 开发团队