带URLSession的PromiseKit

时间:2019-10-08 11:12:09

标签: swift urlsession promisekit

在我的远程服务返回401的情况下,我试图添加对响应状态代码的检查。

我正在尝试使用PromiseKit URLSession扩展名。

想象一下我有一些基本的东西

        return firstly {
            URLSession.shared.dataTask(.promise, with: request)
        }.compactMap {
            try JSONDecoder().decode(T.self, from: $0.data)
        }

我想做的是添加对响应状态代码的检查,这样我可能会抛出错误并执行一些进一步的步骤。

类似

        return firstly {
            URLSession.shared.dataTask(.promise, with: request)
        }.map { session  in
            if (session.response as? HTTPURLResponse)?.statusCode == 401 {
                // throw a custom error here
                // something like
                // throw TokenProviderError.unauthorized
            }

            return session.data

        }.compactMap {
            try JSONDecoder().decode(T.self, from: $0)
        }.catch { error in
            // check the error thrown here and do something
        }

这是一个例外

  

无法将类型为'PMKFinalizer'的返回表达式转换为返回类型   “承诺”

是否可以引入类似retryWhen的内容,使我能够发现错误并进行检查?

2 个答案:

答案 0 :(得分:1)

我试图实现与您完全相同的目标,我认为您正在寻找的retrywhen功能称为recover,您可以在GitHub PromiseKit Document中找到它

  • 请注意,以下代码未通过编辑器,可能无法编译,我仅使用此代码来演示流程。
return firstly {
            URLSession.shared.dataTask(.promise, with: request)
        }.map { session  in
            if (session.response as? HTTPURLResponse)?.statusCode == 401 {
                throw TokenProviderError.unauthorized
            }
            return session.data
        }.compactMap {
            try JSONDecoder().decode(T.self, from: $0)
        }
        // above is a copy of your code
        .recover { error in // instead of .catch, use .recover here
            guard let err = error as? TokenProviderError,
                  err == .unauthorized 
                  else { throw error } // we only care 401 error here, other error will be handled in caller's .catch

            // in my case, the reason for 401 error is due to an expired access token, so I will try to use refresh token to get a valid access token and make the same request again
            return firstly {
                loginWithRefreshToken(token: myRefreshToken)
            }.then { loginRes -> Promise<(data: Data, response: URLResponse)> in
                // loginRes contains new access token, set it to request "Authorization" header, and make the same request again
                request.setValue(loginRes.accessToken, forHTTPHeaderField: "Authorization")
                return URLSession.shared.dataTask(.promise, with: request)
            }.map { session -> Data in
                return session.data
            }.compactMap { data -> Promise<T> in
                try JSONDecoder().decode(T.self, from: data)
            }
        }

也许答案来得有点晚,但是我希望它可以帮助像我一样对PromiseKit陌生的一些编码人员。

答案 1 :(得分:0)

由于.catch不返回任何内容,但您想返回一个Promise<T>,因此您必须在此处删除.catch

return firstly {
    URLSession.shared.dataTask(.promise, with: request)
}.map { session  in
    if (session.response as? HTTPURLResponse)?.statusCode == 401 {
        // throw a custom error here
        // something like
        // throw TokenProviderError.unauthorized
    }

    return session.data

}.compactMap {
    try JSONDecoder().decode(T.self, from: $0)
}

.catch将由被调用者实现。


或者,也许您正在寻找类似的东西

func test() -> Promise<Any> {
    return firstly(execute: { () -> Promise<String> in
        return .value("bhai")
    }).map({ string -> Promise<Double?> in
        return .value(0.1)
    }).compactMap({ double -> NSError in
        return NSError(domain: "", code: 0, userInfo: nil)
    })
}