【问题标题】:How to add header in Apollo GraphQL : iOS如何在 Apollo GraphQL 中添加标题:iOS
【发布时间】:2019-08-19 02:31:52
【问题描述】:

我正在一个使用Apollo GraphQL 方法的项目中工作,并且工作正常。但现在客户端需要使用 Apollo API 添加额外的标头。但在添加标头后,API 的响应返回为 unAuthorized

我将标题添加为,

    let apolloAuth: ApolloClient = {
        let configuration = URLSessionConfiguration.default

        // Add additional headers as needed
        configuration.httpAdditionalHeaders = ["Authorization" : self.singleTonInstance.token]
        configuration.httpAdditionalHeaders = ["channel" : "mobile"]

        let url = URL(string: "http://xxx/graphql")!

        return ApolloClient(networkTransport: HTTPNetworkTransport(url: url, configuration: configuration))

    }()

请任何人帮助我了解如何使用 Apollo GraphQL 添加标题。

【问题讨论】:

  • 您是否尝试将标头设置为“Bearer ”而不是“”?您的服务器使用的授权方法是什么?您是否有针对使用授权令牌的服务器的有效 cURL 语句?
  • 你找到解决办法了吗?
  • 请参考我的回答。

标签: ios graphql apollo apollo-client


【解决方案1】:

我终于找到了答案。按如下方式添加表头,

 let apolloAuth: ApolloClient = {
        let configuration = URLSessionConfiguration.default

        let token = UserDefaults.standard.value(forKey: "token")
        // Add additional headers as needed
        configuration.httpAdditionalHeaders = ["authorization":"\(token!)", "channel":"mobile"]
        let url = URL(string: "http://xxxx/graphql")!

        return ApolloClient(networkTransport: HTTPNetworkTransport(url: url, configuration: configuration))

    }()

希望对某人有所帮助。

【讨论】:

  • 从 0.34 版开始停止工作,不再有 HTTPNetworkTransport
【解决方案2】:

现在接受的解决方案已经过时,因为 HTTPNetworkTransport 不再接受配置参数,而是直接接受 URLSession 而不是 URLSessionConfiguration

这是一个示例,如何在每个请求上向 Apollo 客户端发送授权标头,如果找到,则从 Apollo 客户端 (iOS) 的 version 0.21.0 中的 UserDefaults 中检索它

import Foundation
import Apollo

class Network {
    static let shared = Network()

    private(set) lazy var apollo: ApolloClient = {
        let token = UserDefaults.standard.string(forKey: "accessToken") ?? ""
        let url = URL(string: "http://localhost:4000/graphql")!

        let configuration = URLSessionConfiguration.default

        configuration.httpAdditionalHeaders = ["authorization": "Bearer \(token)"]

        return ApolloClient(
            networkTransport: HTTPNetworkTransport(url: url, session: URLSession(configuration: configuration))
        )
    }()
}

【讨论】:

    【解决方案3】:

    更新:此解决方案在“Apollo Client v0.34.0”之后被弃用

    以前的答案很旧,现在通过委托完成:

    “此协议允许对请求进行飞行前验证、在修改请求之前退出的能力以及使用附加标头等内容修改 URLRequest 的能力。”

    import Foundation
    import Apollo
    
        final class Network {
            static let shared = Network()
            private lazy var networkTransport: HTTPNetworkTransport = {        
    
            let transport = HTTPNetworkTransport(url: URL(string: "https://example.com/graphql")!)
            transport.delegate = self
    
            return transport
        }()
    
        private(set) lazy var apollo = ApolloClient(networkTransport: self.networkTransport)
    }
    
    extension Network: HTTPNetworkTransportPreflightDelegate {
        func networkTransport(_ networkTransport: HTTPNetworkTransport, shouldSend request: URLRequest) -> Bool {
            return true
        }
    
        func networkTransport(_ networkTransport: HTTPNetworkTransport, willSend request: inout URLRequest) {
            var headers = request.allHTTPHeaderFields ?? [String: String]()
            headers["Authorization"] = "Bearer \(YOUR_TOKEN)"
    
            request.allHTTPHeaderFields = headers
        }
    }
    

    这里是文档的链接以了解更多详细信息:

    https://www.apollographql.com/docs/ios/initialization/

    【讨论】:

    • 收到此错误 Cannot find type 'HTTPNetworkTransport' in scopeCannot find type 'HTTPNetworkTransportPreflightDelegate' in scope 有什么帮助吗?我正在使用 Appoloclient v0.34.1。
    • @GB 我查看了上面链接中的文档,他们已经弃用了 HTPPNetworkTransport。这仍然可以使用“LegacyInterceptorProvider”来完成,或者您可以查看新协议:NetworkTransport”。
    • 我提供了一个解决方案你可以看看。
    【解决方案4】:

    从 Apollo Client v0.34.0 及更高版本开始,之前提供的代码将无法工作,因为他们重写了过去的工作方式。这对我有用...有关更多信息,请考虑通过链接 here 中的此文档。

    class Network {
      static let shared = Network()
      
        private(set) lazy var apollo: ApolloClient = {
            let client = URLSessionClient()
            let cache = InMemoryNormalizedCache()
            let store = ApolloStore(cache: cache)
            let provider = NetworkInterceptorProvider(client: client, store: store)
            let url = URL(string: "https://www.graphqlapi.com/")!
            let transport = RequestChainNetworkTransport(interceptorProvider: provider,
                                                         endpointURL: url)
            return ApolloClient(networkTransport: transport)
        }()
    }
    
    class NetworkInterceptorProvider: LegacyInterceptorProvider {
        override func interceptors<Operation: GraphQLOperation>(for operation: Operation) -> [ApolloInterceptor] {
            var interceptors = super.interceptors(for: operation)
            interceptors.insert(CustomInterceptor(), at: 0)
            return interceptors
        }
    }
    
    class CustomInterceptor: ApolloInterceptor {
        // Find a better way to store your token this is just an example
        let token = "YOUR TOKEN"
        
        func interceptAsync<Operation: GraphQLOperation>(
            chain: RequestChain,
            request: HTTPRequest<Operation>,
            response: HTTPResponse<Operation>?,
            completion: @escaping (Result<GraphQLResult<Operation.Data>, Error>) -> Void) {
            
            request.addHeader(name: "authorization", value: "Bearer: \(token)")
    
            chain.proceedAsync(request: request,
                               response: response,
                               completion: completion)
        }
    }
    

    【讨论】:

      【解决方案5】:

      更新:“Apollo Client v0.41.0”和“Swift 5”的解决方案

      我在使用 Apollo Client v0.41.0 和 Swift 5.0 时遇到了同样的问题,但上述解决方案均无效。经过数小时的试用后终于能够找到解决方案。以下解决方案使用 Apollo Client v0.41.0 和 Swift 5 进行测试

      import Foundation
      import Apollo
      
      class Network {
          static let shared = Network()
          
          private(set) lazy var apollo: ApolloClient = {
      
              let cache = InMemoryNormalizedCache()
              let store1 = ApolloStore(cache: cache)
              let authPayloads = ["Authorization": "Bearer <<TOKEN>>"]
              let configuration = URLSessionConfiguration.default
              configuration.httpAdditionalHeaders = authPayloads
              
              let client1 = URLSessionClient(sessionConfiguration: configuration, callbackQueue: nil)
              let provider = NetworkInterceptorProvider(client: client1, shouldInvalidateClientOnDeinit: true, store: store1)
              
              let url = URL(string: "https://<HOST NAME>/graphql")!
              
              let requestChainTransport = RequestChainNetworkTransport(interceptorProvider: provider,
                                                                       endpointURL: url)
              
              return ApolloClient(networkTransport: requestChainTransport,
                                  store: store1)
          }()
      }
      class NetworkInterceptorProvider: DefaultInterceptorProvider {
          override func interceptors<Operation: GraphQLOperation>(for operation: Operation) -> [ApolloInterceptor] {
              var interceptors = super.interceptors(for: operation)
              interceptors.insert(CustomInterceptor(), at: 0)
              return interceptors
          }
      }
      
      class CustomInterceptor: ApolloInterceptor {
          
          func interceptAsync<Operation: GraphQLOperation>(
              chain: RequestChain,
              request: HTTPRequest<Operation>,
              response: HTTPResponse<Operation>?,
              completion: @escaping (Swift.Result<GraphQLResult<Operation.Data>, Error>) -> Void) {
              request.addHeader(name: "Authorization", value: "Bearer <<TOKEN>>")
              
              print("request :\(request)")
              print("response :\(String(describing: response))")
              
              chain.proceedAsync(request: request,
                                 response: response,
                                 completion: completion)
          }
      }
      

      【讨论】:

      • 谢谢!这是唯一适用于 Apollo 0.42.0 的解决方案
      • @Chamath Jeevan 我已经用 Apollo 0.43.0 版本尝试过这个解决方案,它给了我失败 reposne 错误 failure(Apollo.LegacyParsingInterceptor.LegacyParsingError.couldNotParseToLegacyJSON(data: 1839 bytes)) 请建议我下一步该怎么做
      • @JochenHolzer 我也尝试过相同的代码语法,但请求在失败块中为我提供了 HTML。你能帮我解决这个问题吗Apollo GraphQL header always gives failure in iOS Swift
      • @Princess 也许 HTML 响应中有错误消息。如果我是你,我会询问端点开发团队服务器日志文件中有哪些关于你失败请求的信息。
      • @JochenHolzer 我正在使用 Shopify GraphQL Admin API 从 Shopify 商店获取客户的订单详细信息。使用 Android Apollo 客户端的相同 URL 请求。
      【解决方案6】:

      导入这两个元素

      import UIKit
      import Apollo
      

      创建一个类网络并粘贴到源代码下面

          struct Network {
          static var request = Network()
          private(set) lazy var apollo: ApolloClient = {
      
              let cache = InMemoryNormalizedCache()
              let store1 = ApolloStore(cache: cache)
              let authPayloads = ["Authorization": "Bearer <TOKEN>"]
              let configuration = URLSessionConfiguration.default
              configuration.httpAdditionalHeaders = authPayloads
              
              let client1 = URLSessionClient(sessionConfiguration: configuration, callbackQueue: nil)
              let provider = NetworkInterceptorProvider(client: client1, shouldInvalidateClientOnDeinit: true, store: store1)
              
              let url = URL(string: "http://xxx/graphql")!
              
              let requestChainTransport = RequestChainNetworkTransport(interceptorProvider: provider,
                                                                       endpointURL: url)
              
              return ApolloClient(networkTransport: requestChainTransport,
                                  store: store1)
          }()
      }
      

      在 Network 类中添加 NetworkInterceptorProvider

      class NetworkInterceptorProvider: LegacyInterceptorProvider {
      override func interceptors<Operation: GraphQLOperation>(for operation: Operation) -> [ApolloInterceptor] {
          var interceptors = super.interceptors(for: operation)
          interceptors.insert(CustomInterceptor(), at: 0)
          return interceptors
      }
      

      }

      在 Network 类中也添加 CustomInterceptor

      class CustomInterceptor: ApolloInterceptor {
      
      func interceptAsync<Operation: GraphQLOperation>(
          chain: RequestChain,
          request: HTTPRequest<Operation>,
          response: HTTPResponse<Operation>?,
          completion: @escaping (Swift.Result<GraphQLResult<Operation.Data>, Error>) -> Void) {
          request.addHeader(name: "Authorization", value: "Bearer <TOKEN>")
          
          print("request :\(request)")
          print("response :\(String(describing: response))")
          
          chain.proceedAsync(request: request,
                             response: response,
                             completion: completion)
      }
      

      }

      最终从 ViewController 调用这个方法

      func todoQueryCloud(){
          Network.request.apollo.fetch(query: ProgressionsQuery()){result in
              // 3
              switch result {
              case .success(let graphQLResult):
                  guard let data = try? result.get().data else { return }
                  if graphQLResult.data != nil {
                      // 4
                      print("Loaded data \(String(describing: data.progressions))")
                      self.collectionView.reloadData()
                  }
                  
              case .failure(let error):
                  // 5
                  print("Error loading data \(error)")
              }
          }
      }
      

      【讨论】:

      猜你喜欢
      • 2021-12-15
      • 2020-07-05
      • 2019-12-08
      • 2018-10-03
      • 2018-03-20
      • 2018-10-04
      • 2021-07-22
      • 2018-02-14
      • 2020-06-29
      相关资源
      最近更新 更多