带有 URLSession 的 PromiseKit

PromiseKit w/ URLSession

如果我的远程服务 returns a 401.

,我正在尝试添加针对响应状态代码的检查

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

假设我有一些基本的东西,比如

        return firstly {
            URLSession.shared.dataTask(.promise, with: request)
        }.compactMap {
            try JSONDecoder().decode(T.self, from: [=10=].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: [=11=])
        }.catch { error in
            // check the error thrown here and do something
        }

这有一个例外

Cannot convert return expression of type 'PMKFinalizer' to return type 'Promise'

是否可以引入类似 retryWhen 的东西,这将使我能够捕获错误并进行检查?

因为 .catch 没有 return 任何东西,但你想要 return 一个 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: [=10=])
}

.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)
    })
}

我试图实现与您所做的完全相同的事情,我认为您正在寻找的 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: [=10=])
        }
        // 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 的编码人员。