使用Vapor实现请求转发:鉴权问题求助
解决Vapor请求透传时的"未授权"问题
问题根源
你当前的代码仅做了最基础的请求转发,但没有把客户端请求里的授权相关头信息(比如Authorization、Cookie)、请求体等关键内容传递给真实服务器,导致真实服务器无法验证请求合法性,返回"未授权"错误。另外固定路径的写法也不够灵活,没法适配多接口的透传需求。
修复方案
1. 基础版:透传关键内容并适配动态路径
func routes(_ app: Application) throws { // 匹配所有POST请求的子路径,支持动态透传 app.post("*") { req async throws -> Response in // 真实服务器基础地址 let realBaseURL = "https://realbase.com" // 拼接原请求的路径到真实服务器地址 guard let targetURL = URL(string: realBaseURL + req.url.path) else { throw Abort(.badRequest, reason: "无效的目标路径") } // 创建转发请求,复用原请求的HTTP方法 var clientRequest = req.client.request(.POST, targetURL) // 透传请求头,排除Vapor内部的Connection头 for (key, value) in req.headers { if key != .connection { clientRequest.headers.add(name: key, value: value) } } // 透传客户端的请求体 if let bodyData = req.body.data { clientRequest.body = .init(data: bodyData) } // 发送请求并返回真实服务器的响应 let response = try await clientRequest.send() return response } }
2. 进阶版:多方法支持+快速切换服务器环境
如果需要支持GET、PUT等更多HTTP方法,并且要方便在真实/模拟服务器间切换,可以抽离配置:
// 定义服务器环境,一键切换 enum ServerEnv { case real case mock var baseURL: String { switch self { case .real: return "https://realbase.com" case .mock: return "http://localhost:3000" // 替换成你的模拟服务器地址 } } } func routes(_ app: Application) throws { // 匹配所有HTTP方法和所有路径 app.on(.GET, .POST, .PUT, .DELETE, "*") { req async throws -> Response in // 切换环境只需修改这里 let targetEnv = ServerEnv.real guard let targetURL = URL(string: targetEnv.baseURL + req.url.path) else { throw Abort(.badRequest) } var clientRequest = req.client.request(req.method, targetURL) // 透传请求头 req.headers.forEach { key, value in if key != .connection { clientRequest.headers.add(name: key, value: value) } } // 透传查询参数 if let queryString = req.url.query { clientRequest.url.append(query: queryString) } // 透传请求体 if let bodyData = req.body.data { clientRequest.body = .init(data: bodyData) } let response = try await clientRequest.send() return response } }
核心注意事项
- 授权头必须透传:真实服务器的鉴权逻辑依赖客户端发送的Authorization、Cookie等头信息,遗漏就会触发未授权错误。
- 过滤内部连接头:Vapor的
Connection头是当前客户端与Vapor服务器的连接标识,不需要透传给真实服务器,否则可能引发连接异常。 - 动态路径匹配:使用
"*"可以匹配所有子路径,不用为每个接口单独编写路由,提升代码扩展性。
内容的提问来源于stack exchange,提问作者DerrickHo328
相关产品推荐
相关产品推荐

