You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Postman可正常请求的Bearer Token认证,Swift App返回401问题排查

问题:Swift App中Bearer Token认证返回401,Postman可正常访问

我用Vapor搭建了服务器,采用Bearer Token认证机制。已经成功登录获取到Token,在Postman中使用该Token能正常访问受保护的/residents路由并得到Resident数组响应,但在Swift App中发起请求却返回401未授权。

我的App请求代码如下:

func getResidents() async throws -> [Resident] {
    let session = URLSession.shared
    var request = URLRequest(url: URL(string: "\(API.url)/residents")!)
    
    request.httpMethod = "GET"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.setValue("Bearer \(token?.value)", forHTTPHeaderField: "Authorization")
        
    // 发起请求
    let (data, response) = try await session.data(for: request)
        
    print(response)
    // 验证响应状态码
    guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
        throw GetResidentsError.unableToGetResidents
    }
    print(httpResponse.statusCode)
        
    let decoder = JSONDecoder()
    let residents = try decoder.decode([Resident].self, from: data)
    
    print(residents)
    return residents
}

Postman中配置Bearer Token的GET请求可正常通过认证(请求头的Authorization字段格式为Bearer [有效Token])。


排查与解决

核心问题:可选值拼接导致Authorization头格式错误

代码中"Bearer \(token?.value)"的写法存在问题:

  • 当token为nil时,会生成Bearer nil的无效认证头;
  • 即使token不为nil,字符串插值对可选值的处理可能引入不必要的格式问题。

修复代码

先确保token及其value存在,再生成正确的Authorization头:

func getResidents() async throws -> [Resident] {
    let session = URLSession.shared
    guard let url = URL(string: "\(API.url)/residents") else {
        throw GetResidentsError.invalidURL
    }
    var request = URLRequest(url: url)
    
    request.httpMethod = "GET"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    
    // 先解包token,避免可选值问题
    guard let tokenValue = token?.value else {
        throw GetResidentsError.missingToken
    }
    request.setValue("Bearer \(tokenValue)", forHTTPHeaderField: "Authorization")
        
    let (data, response) = try await session.data(for: request)
        
    guard let httpResponse = response as? HTTPURLResponse else {
        throw GetResidentsError.invalidResponse
    }
    print("响应状态码:\(httpResponse.statusCode)")
    
    guard httpResponse.statusCode == 200 else {
        throw GetResidentsError.unableToGetResidents
    }
        
    let decoder = JSONDecoder()
    let residents = try decoder.decode([Resident].self, from: data)
    
    return residents
}

额外排查点

  1. Token一致性:确认tokenValue和Postman中使用的Token完全一致,无空格、换行或大小写差异;
  2. URL正确性:检查请求URL是否和Postman中的完全相同,包括协议(HTTP/HTTPS)、路径拼写;
  3. 打印验证:添加打印语句确认最终的Authorization头格式:
print("Authorization头:\(request.value(forHTTPHeaderField: "Authorization") ?? "无认证头")")

内容的提问来源于stack exchange,提问作者AFinch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 00:43:32