# cors-proxy **Repository Path**: ernestX/cors-proxy ## Basic Information - **Project Name**: cors-proxy - **Description**: 一个基于 Ktor 框架的 CORS 代理服务器,用于解决跨域资源共享 (CORS) 问题。该服务器可以代理任意 HTTP/HTTPS 请求,并自动处理 CORS 头。 - **Primary Language**: Kotlin - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-03-18 - **Last Updated**: 2026-03-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # CORS 代理服务器 (Ktor) 一个基于 Ktor 框架的 CORS 代理服务器,用于解决跨域资源共享 (CORS) 问题。该服务器可以代理任意 HTTP/HTTPS 请求,并自动处理 CORS 头。 ## 功能特性 ✅ **完整的CORS支持** - 支持所有HTTP方法 (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS) ✅ **灵活的代理** - 支持动态代理任意URL或配置固定上游服务器 ✅ **请求/响应头转发** - 智能转发请求和响应头 ✅ **错误处理** - 完善的错误处理和日志记录 ✅ **健康检查** - 内置健康检查端点 ✅ **Docker容器化** - 基于Alpine Linux的轻量级Docker镜像 ✅ **环境变量配置** - 支持通过环境变量灵活配置 ## 快速开始 ### 使用 Docker Compose(推荐) #### 1. 克隆或获取项目文件 ```bash git clone cd cors-proxy ``` #### 2. 直接启动容器 ```bash docker-compose up -d ``` #### 3. 验证服务 ```bash curl http://localhost:8888/health ``` ### 使用 Docker 命令 #### 1. 构建镜像 ```bash docker build -t cors-proxy:latest . ``` #### 2. 运行容器 ```bash docker run -d \ --name cors-proxy \ -p 8888:8888 \ cors-proxy:latest ``` 使用API_PROXY_URL环境变量: ```bash docker run -d \ --name cors-proxy \ -p 8888:8888 \ -e API_PROXY_URL=https://api.example.com \ cors-proxy:latest ``` ### 本地开发运行 #### 前置条件 - JDK 21 或更高版本 - Gradle 8.5 或更高版本 #### 构建项目 ```bash gradle build ``` #### 运行应用 ```bash gradle run ``` 或者运行JAR文件: ```bash gradle shadowJar java -jar build/libs/cors-proxy-1.0.0-all.jar ``` ## 使用方法 ### 1. 动态代理任意URL 使用 `/proxy` 端点代理请求到任意URL。 **请求示例:** ```bash # GET请求 curl "http://localhost:8888/proxy?url=https://api.github.com/users/octocat" # POST请求 curl -X POST \ "http://localhost:8888/proxy?url=https://api.example.com/api/data" \ -H "Content-Type: application/json" \ -d '{"name":"test","value":123}' # 使用URL编码的URL参数 curl "http://localhost:8888/proxy?url=https%3A%2F%2Fapi.example.com%2Fendpoint%3Fparam%3Dvalue" ``` **响应示例:** ```json { "status": "ok", "data": "..." } ``` ### 2. 使用API_PROXY_URL环境变量 配置 `API_PROXY_URL` 环境变量以自动代理 `/api/*` 路由到指定的服务器。 **启动方式:** ```bash # 使用Docker docker run -d \ -p 8888:8888 \ -e API_PROXY_URL=https://api.example.com \ cors-proxy:latest # 或修改docker-compose.yml中的environment配置 ``` **请求示例:** 假设设置了 `API_PROXY_URL=https://api.github.com` ```bash # 请求 /api/users/octocat # 将被转发到 https://api.github.com/users/octocat curl "http://localhost:8888/api/users/octocat" ``` ### 3. 健康检查 ```bash curl http://localhost:8888/health ``` **响应:** ```json { "status": "ok", "message": "CORS Proxy is running" } ``` ## API 端点 ### GET/POST/PUT/DELETE/PATCH /proxy **参数:** - `url` (必需, query参数): 目标URL **支持的HTTP方法:** - GET - POST - PUT - DELETE - PATCH - HEAD - OPTIONS (自动CORS处理) **请求头转发:** - Content-Type - Authorization - Accept - Accept-Language - X-Custom-Header - 等其他自定义头 **响应头转发:** - Content-Type - Content-Length - X-Custom-Header - 目标服务器返回的所有公开头 ### GET /health 健康检查端点 **响应:** ```json { "status": "ok", "message": "CORS Proxy is running" } ``` ### GET/POST /api/{path...} 使用环境变量 `API_PROXY_URL` 代理请求(需要配置) ## CORS 配置 服务器配置了以下CORS策略: ``` - 允许所有源 (*) - 允许所有HTTP方法 - 允许自定义请求头 - 允许暴露响应头 - 最大缓存时间: 3600秒 ``` ### 自定义CORS配置 修改 `src/main/kotlin/ernest/corsproxy/Application.kt` 中的 `install(CORS)` 部分: ```kotlin install(CORS) { // 限制特定域名 allowHost("example.com") allowHost("app.example.com") // 允许特定HTTP方法 allowMethod(HttpMethod.Get) allowMethod(HttpMethod.Post) // 允许特定请求头 allowHeader(HttpHeaders.ContentType) allowHeader(HttpHeaders.Authorization) // 暴露响应头 exposeHeader(HttpHeaders.ContentType) // 设置缓存时间 maxAgeInSeconds = 3600 } ``` ## 环境变量 | 变量名 | 说明 | 可选/必需 | 示例 | |------|------|---------|------| | `API_PROXY_URL` | 上游API服务器地址,用于 `/api/*` 路由 | 可选 | `https://api.example.com` | | `PORT` | 服务器监听端口 (Docker中固定8888) | 可选 | `8888` | ## Docker 相关命令 ### 查看容器日志 ```bash docker logs cors-proxy # 实时查看 docker logs -f cors-proxy ``` ### 停止容器 ```bash docker stop cors-proxy ``` ### 删除容器 ```bash docker rm cors-proxy ``` ### 查看容器状态 ```bash docker ps ``` ### 进入容器 ```bash docker exec -it cors-proxy sh ``` ### Docker Compose 常用命令 ```bash # 启动服务 docker-compose up -d # 停止服务 docker-compose down # 查看日志 docker-compose logs -f cors-proxy # 重启服务 docker-compose restart cors-proxy ``` ## 项目结构 ``` cors-proxy/ ├── src/ │ └── main/ │ ├── kotlin/ │ │ └── ernest/ │ │ └── corsproxy/ │ │ └── Application.kt # 主应用文件 │ └── resources/ │ └── logback.xml # 日志配置 ├── build.gradle.kts # Gradle构建文件 ├── gradle.properties # Gradle配置 ├── settings.gradle.kts # Gradle设置 ├── Dockerfile # Docker构建文件 ├── docker-compose.yml # Docker Compose配置 ├── .dockerignore # Docker忽略文件 └── README.md # 本文件 ``` ## 构建信息 - **语言**: Kotlin - **框架**: Ktor 2.3.7 - **JDK**: OpenJDK 21 - **基础镜像**: alpine:latest (带OpenJDK 21) - **构建工具**: Gradle 8.5 - **镜像大小**: ~400MB (包含JDK) ## 性能优化 ### Docker 多阶段构建 Dockerfile使用多阶段构建来减小镜像大小: 1. **构建阶段**: 使用完整的Gradle+JDK镜像构建应用 2. **运行阶段**: 基于Alpine Linux的轻量级镜像,仅包含运行时所需的内容 ### 内存和CPU限制 在 `docker-compose.yml` 中配置资源限制: ```yaml deploy: resources: limits: memory: 512M reservations: memory: 256M ``` ## 日志 日志输出到标准输出,可以通过以下方式查看: ```bash # 实时查看日志 docker logs -f cors-proxy # 查看最后100行日志 docker logs --tail 100 cors-proxy ``` 日志级别可在 `src/main/resources/logback.xml` 中配置。 ## 常见问题 ### Q: 如何修改CORS策略? A: 编辑 `src/main/kotlin/ernest/corsproxy/Application.kt` 中的 `install(CORS)` 部分,然后重新构建Docker镜像。 ### Q: 如何设置代理服务器的用户名和密码? A: 在请求中包含 Authorization 头,服务器会自动转发给目标服务器: ```bash curl -H "Authorization: Bearer token" "http://localhost:8888/proxy?url=..." ``` ### Q: 容器无法访问外网? A: 确保Docker容器有网络访问权限。检查Docker网络设置或使用 `--network host`。 ### Q: 如何监控容器状态? A: 使用健康检查端点: ```bash curl http://localhost:8888/health ``` ### Q: 如何修改监听端口? A: 在 `docker-compose.yml` 或 `docker run` 命令中修改端口映射: ```bash docker run -p 8888:8888 cors-proxy:latest ``` ## 安全建议 ⚠️ **生产环境注意事项:** 1. **限制CORS来源**:不要使用 `anyHost()`,应配置具体的域名 2. **限制代理URL**:添加URL白名单验证 3. **使用HTTPS**:在生产环境中使用HTTPS 4. **认证授权**:添加API密钥或其他认证机制 5. **请求超时**:设置合理的请求超时时间 6. **速率限制**:考虑添加速率限制功能 7. **日志监控**:监控异常请求和错误日志 示例:添加URL白名单 ```kotlin val allowedDomains = listOf("api.example.com", "api.github.com") suspend fun handleProxyRequest(call: ApplicationCall, client: HttpClient, method: String) { val targetUrl = call.request.queryParameters["url"] ?: return val domain = URL(targetUrl).host if (!allowedDomains.contains(domain)) { call.respond(HttpStatusCode.Forbidden, mapOf("error" to "Domain not allowed")) return } // ... } ``` ## 许可证 MIT License ## 贡献 欢迎提交Issue和Pull Request! ## 联系方式 如有问题,请提交Issue或联系开发者。