如果先前的请求未经授权,如何执行快速合并请求
Posted
技术标签:
【中文标题】如果先前的请求未经授权,如何执行快速合并请求【英文标题】:How to execute swift combine request if previous request unauthorised 【发布时间】:2021-04-05 12:56:51 【问题描述】:我的出发点是这样的方法foo()
这里的例子。我正在使用retries: 1
。
func foo()
// create url ...
let urlRequest = URLRequest(for: url, httpMethod: "POST", resource: nil, token: accessToken)
let combineRequest = CombineRequest(auth: auth)
combineRequest.runWithResponseStatus(urlRequest, checkStatusCode: 201, retries: 1)
.sink completion in
switch completion
case .finished:
break
case .failure(let error):
self.toasts.insert(ToastText(type: .error, text: Text("\(error.localizedDescription)")), at: 0)
self.clearToasts()
receiveValue: _ in
// successful
.store(in: &cancellables)
所以这是一个 POST
合并请求 (runWithResponseStatus()
)。当我收到401 - unauthorized
时,我想执行另一个合并请求 (refresh()
)。
-
如果
refresh()
成功,它应该执行auth.setAccessToken(to: newAccessToken.token)
并重试之前调用的(runWithResponseStatus()
)方法一次。
现在,在.failure
上,我正在执行print("\(error.localizedDescription)")
,但我想在链中返回该错误,因此它最终会出现在foo()
方法中,我可以将其放入 toasts 数组中.
有人知道如何实现这两点,并且如果可能的话,利用结合的力量让它更干净吗?
struct CombineRequest
var auth: Auth
var jsonDecoder: JSONDecoder = JSONDecoder(dateFormatter: .isoDateFormatter)
func runWithResponseStatus(_ request: URLRequest, checkStatusCode statusCode: Int = 200, queue: DispatchQueue = .main, retries: Int = 0) -> AnyPublisher<(data: Data, response: URLResponse), Error>
var cancellable = Set<AnyCancellable>()
return URLSession.shared.dataTaskPublisher(for: request)
.retry(retries)
.tryMap output in
if let response = output.response as? HTTPURLResponse, response.statusCode != statusCode
switch response.statusCode
case 401:
try refresh(decodingType: AccessData.self)
.sink completion in
switch completion
case .finished:
break
case .failure(let error):
print("\(error.localizedDescription)")
receiveValue: newAccessToken in
auth.setAccessToken(to: newAccessToken.token)
.store(in: &cancellable)
case 400:
throw ResourceError.internalServerError("General.error.general")
default:
throw ResourceError.httpStatus(response.statusCode)
return output
.receive(on: queue)
.eraseToAnyPublisher()
private func refresh<DecodingType>(checkStatusCode statusCode: Int = 200, queue: DispatchQueue = .main, decodingType: DecodingType.Type) throws -> AnyPublisher<DecodingType, Error> where DecodingType: Decodable
// prepare all properties ...
return URLSession.shared.dataTaskPublisher(for: refreshRequest)
.tryMap output in
if let response = output.response as? HTTPURLResponse, response.statusCode != statusCode
switch response.statusCode
case 401:
auth.loggedOut()
case 400:
throw ResourceError.internalServerError("General.error.general")
default:
auth.loggedOut()
throw ResourceError.httpStatus(response.statusCode)
return output.data
.decode(type: DecodingType.self, decoder: jsonDecoder)
.receive(on: queue)
.eraseToAnyPublisher()
【问题讨论】:
你找到解决这个问题的方法了吗?我在这里遇到了类似的问题 - ***.com/questions/67076317/… @Rocky 不幸的是没有。嗯,我明白了,这实际上是我们想要解决的同一个问题。执行请求,如果未经授权,刷新令牌并再次尝试上一个请求。 【参考方案1】:我相信你可以catch
或replaceError
。试试看这个:https://www.donnywals.com/catch-vs-replaceerror-in-combine/
【讨论】:
以上是关于如果先前的请求未经授权,如何执行快速合并请求的主要内容,如果未能解决你的问题,请参考以下文章
如何使 Vert.x JWTAuthHandler 只注入用户对象而不拒绝未经授权的请求?