Get response header with Moya

2020-05-09 03:25发布

问题:

I am using Moya in my swift app for network requests.

I am able to get requests and map the result using Moya- Object Mapper.

I have used alamofire earlier and I am familiar with how to make post, get requests and read the response headers .

However, I can't seem to understand how I can do the same in Moya.

I did go through the documentation but it does not say anything about reading response headers.

Is there any example or tutorial where I can follow how to do a HTTP authentication and read the response headers. And also on how I can make post requests and send parameters as field parameters or json body.

I have already gone through the Moya example.

Any help will be appreciated. Thank you.

回答1:

Response header in Moya is in fact quite hard for the moment. It's a unwanted old downcast in Moya code. I never know why they downcasted it.

I opened a related issue to point it out: Moya header

And do some change thanks to a pull request: Moya header PR

This is an example of my personal code where I forcecast the response to get access to the headers:

class GetTokenRequest {

    private let requestService = AuthorizedRequest()

    func request() -> Observable<AuthorizedResult<GetTokenEntityResult>> {
        return Observable.deferred { [weak self] in
            guard let wself = self else {
                return Observable.empty()
            }

            let req = wself.requestService.makeRawRequest { userId in
                    let obj = GetTokenEntity(lang: currentLanguage(), userId: userId)
                    return MtxAPI.getToken(obj)
                }
                .shareReplay(1)

            return req.map { result in
                switch result {
                case .success(let response):
                    let urlResponse = response.response as! HTTPURLResponse
                    guard let token = urlResponse.allHeaderFields["Token"] as? String else {
                        return AuthorizedResult.fail(RequestError.technical)
                    }
                    return AuthorizedResult.success(GetTokenEntityResult(token: token))

                case .fail(let error): return AuthorizedResult.fail(error)
                }
            }
        }
    }

}

I'm using RxSwift but the main line is:

let urlResponse = response.response as! HTTPURLResponse

You may forcecast it in your map/mapObject/mapArray you use when you get the response (which is a Moya.Response)

I suggest to you to follow the issue I made, to know when it will be implemented in the next release which will contain this breaking change

Bonus: if you use SwiftLint in your project, you may cast it with a guard/let

guard let resp = response.response as? HTTPURLResponse


回答2:

If anyone still interested how to get url request object when using Moya, here is yet another implementation:

extension NetworkApiService {
public var urlRequest: URLRequest {
    let defaultURL: URL
    if path.isEmpty {
        defaultURL = baseURL
    } else {
        defaultURL = baseURL.appendingPathComponent(path)
    }

    let endpoint = MoyaProvider.defaultEndpointMapping(for: self)
    do {
        return try endpoint.urlRequest()
    } catch {
        return URLRequest(url: defaultURL)
    }
}
}

Where NetworkApiService conforms to Moya's TargetType protocol.

Please take a note, that returned instance is not exactly same URLRequest object that called by Moya's engine, but it is instantiated using Moya's API and will have same configuration as original one.



回答3:

The easiest way to get response headers in Moya is

switch result {
case let .success(moyaResponse):
     if(moyaResponse.statusCode == 200) {
          let response = moyaResponse.response
          let responseHeaderDictionary = response?.allHeaderFields
     }
}