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

Apollo GraphQL iOS:认证查询请求未发送问题求助

排查未发送的带认证GraphQL请求(iOS Apollo)

问题背景

无GraphQL经验,尝试发起带认证的GraphQL查询,但请求未发送:Proxyman无记录,无任何成功/失败回调。已参照官方逻辑编写代码,断点显示拦截器已加入NetworkChain,代码生成验证正常。

相关代码实现

Network类与拦截器代码

public final class Network {

    public static let shared = Network()

    public static func authenticatedApollo(_ authenticationData: GraphQLAuthenticationData) -> ApolloClient {
        let client = URLSessionClient()
        let cache = InMemoryNormalizedCache()
        let store = ApolloStore(cache: cache)
        let provider = NetworkAuthenticatedInterceptorProvider(client: client, store: store, authenticationData: authenticationData)
        let url = URL(string: "my instance url")!
        let transport = RequestChainNetworkTransport(interceptorProvider: provider, endpointURL: url)

        return ApolloClient(networkTransport: transport, store: store)
    }
}

private class AuthorizationInterceptor: ApolloInterceptor {
    public var id: String

    private let authenticationData: GraphQLAuthenticationData

    init(id: String = UUID().uuidString, authenticationData: GraphQLAuthenticationData) {
        self.id = id
        self.authenticationData = authenticationData
    }

    func interceptAsync<Operation>(chain: RequestChain,
                                   request: HTTPRequest<Operation>,
                                   response: HTTPResponse<Operation>?,
                                   completion: @escaping (Result<GraphQLResult<Operation.Data>, Error>) -> Void)
    where Operation: GraphQLOperation {
        request.addHeader(name: "Authorization", value: authenticationData.token)
        // adding other headers
        chain.proceedAsync(request: request, response: response, interceptor: self, completion: completion)
    }
}

private class NetworkAuthenticatedInterceptorProvider: DefaultInterceptorProvider {

    private let authenticationData: GraphQLAuthenticationData

    init(client: URLSessionClient = URLSessionClient(), shouldInvalidateClientOnDeinit: Bool = true, store: ApolloStore, authenticationData: GraphQLAuthenticationData) {
        self.authenticationData = authenticationData
        super.init(client: client, shouldInvalidateClientOnDeinit: shouldInvalidateClientOnDeinit, store: store)
    }

    override func interceptors<Operation>(for operation: Operation) -> [ApolloInterceptor] where Operation: GraphQLOperation {
        var interceptors = super.interceptors(for: operation)
        let interceptor = AuthorizationInterceptor(authenticationData: authenticationData)
        interceptors.insert(interceptor, at: 0)
        return interceptors
    }
}

查询执行代码

Network.authenticatedApollo(authenticationData).fetch(query: DemoAuthenticatedCallQuery(), cachePolicy: .fetchIgnoringCacheData) {result in
    switch result {
    case .success(let data):
        print("🛸 authenticated data: <...>)")
    case .failure(let error):
        print("🛸 authenticated error: \(error.localizedDescription)")
    }
}

排查建议

  • 验证目标URL有效性:确认"my instance url"是完整且可连通的地址,无拼写错误、缺失端口或路径。可直接在浏览器/Postman中测试该URL的连通性。
  • 修复ApolloClient生命周期问题:当前authenticatedApollo每次调用都会生成新的ApolloClient实例,执行fetch后无强引用持有该实例,会导致客户端被提前释放,请求静默取消。需在调用类中持有强引用:
    // 在调用类中添加属性
    private var apolloClient: ApolloClient?
    
    // 执行请求时
    apolloClient = Network.authenticatedApollo(authenticationData)
    apolloClient?.fetch(query: DemoAuthenticatedCallQuery(), cachePolicy: .fetchIgnoringCacheData) { result in
        // 回调处理逻辑
    }
    
  • 添加拦截器执行日志:在AuthorizationInterceptor的interceptAsync方法中添加日志,确认拦截器是否真正执行,同时检查请求头是否正确添加:
    func interceptAsync<Operation>(chain: RequestChain,
                                   request: HTTPRequest<Operation>,
                                   response: HTTPResponse<Operation>?,
                                   completion: @escaping (Result<GraphQLResult<Operation.Data>, Error>) -> Void)
    where Operation: GraphQLOperation {
        print("AuthorizationInterceptor triggered, token: \(authenticationData.token)")
        request.addHeader(name: "Authorization", value: authenticationData.token)
        print("Request headers: \(request.allHTTPHeaderFields ?? [:])")
        chain.proceedAsync(request: request, response: response, interceptor: self, completion: completion)
    }
    
  • 检查URLSession配置:默认URLSessionClient使用系统默认配置,若存在代理、SSL校验或超时设置问题,可能导致请求静默失败。可自定义配置传入:
    let configuration = URLSessionConfiguration.default
    configuration.timeoutIntervalForRequest = 30
    let client = URLSessionClient(sessionConfiguration: configuration)
    
  • 确认认证数据格式:检查authenticationData.token是否为空,以及格式是否符合服务端要求(比如Bearer Token需要带Bearer 前缀)。
  • 启用Apollo调试日志:创建RequestChainNetworkTransport时开启调试日志,查看请求的完整流程:
    let transport = RequestChainNetworkTransport(
        interceptorProvider: provider,
        endpointURL: url,
        debugLog: { print("Apollo debug: \($0)") }
    )
    
  • 检查App网络权限:确认Info.plist中配置了正确的网络权限(如非HTTPS地址需配置NSAppTransportSecurity,iOS 14+需对应权限配置)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 16:11:46