轮询 url 直到响应为某个值
Poll url until response is a certain value
我刚刚开始用 Swift(一种非常好的语言)编码,我正在尝试制作一个需要用户使用第三方登录服务登录的应用程序。
身份验证流程的基础如下所示:
1. 用户输入 ssn(瑞典人编号)并回车。
2. POST 到 url return 是 json blob:
{
"transactionId": "a transaction id",
"expires": "date sting in some iso format",
"autostartToken": "irrelevant for my usage"
}
3。轮询使用步骤 2 中的 transactionId
的 url。
这个 url return 是一个 json blob:
{
"state": "OUTSTANDING_TRANSACTION",
// other stuff that's uninteresting
}
一旦用户使用移动身份验证应用授予访问权限,此 url 将 return 成为一个更复杂的 json blob。 state
将变为 "COMPLETED"。
4. 从最终的 url 接收身份验证令牌,该令牌可以从步骤 3 中的 blob 获得(一旦状态为 "COMPLETED".
5.???
6. 利润!
所以我的 "problem" 是我无法真正弄清楚(以我有限的 swift 知识)如何执行第 3 步。轮询 url 直到状态为 "COMPLETED"(或者步骤 2 的过期已通过,应该会失败)。
我在 javascript 中做了一次 hacky 尝试来试用该服务,它看起来像这样:
this.postMethodThatReturnsAPromise(url, data).then(response => {
let {transactionId} = response.body;
let self = this,
max = 10,
num = 0;
return new Promise(function (resolve, reject) {
(function poll() {
self._get(`baseurl/${transactionId}`).then(res => {
let {state} = res.body;
if (state !== 'COMPLETE' && num < max) {
setTimeout(poll, 2000);
} else if (state === 'COMPLETE') {
return resolve(res);
}
});
num++;
})();
});
})
如何在 swift 3 中使用 Alamofire 和 Promisekit 执行此操作?
return Alamofire.request(url, method: .post, /* rest is omitted */).responseJSON().then { response -> String in
let d = res as! Dictionary<String, Any>
return d["transactionId"]
}.then { transactionId -> [String: Any] in
// TODO: The polling until blob contains "state" with value "COMPLETED"
// Return the final json blob as dict to the next promise handler
}.then { data in
}
这是我想出的方法,似乎工作正常。
}.then { transactionId -> Promise<PMKDataResponse> in
var dataDict: Dictionary<String, Any> = ["state": "unknown"]
return Promise { fullfill, reject in
func poll() {
// Method that fires an Alamofire get request and returns a Promise<PMKDataResponse>
self._get("baseurl/\(transactionId)").then { response -> Void in
// .toDictionary() is a extension to Data that converts a Data into a dictionary.
dataDict = response.data.toDictionary()
let state: String = dataDict["state"] as! String
if (state != "COMPLETE") {
after(interval: 2).then {
poll()
}
} else if (state == "COMPLETE") {
fullfill(response)
}
}
}
poll()
}
}
显然这不会检查交易的到期日期,但现在没问题。哦,缺少错误处理...
这是这个想法的一个很好的通用版本:
发件人:https://gist.github.com/dtartaglia/2b19e59beaf480535596
/**
Repeadetly evaluates a promise producer until a value satisfies the predicate.
`promiseWhile` produces a promise with the supplied `producer` and then waits
for it to resolve. If the resolved value satifies the predicate then the
returned promise will fulfill. Otherwise, it will produce a new promise. The
method continues to do this until the predicate is satisfied or an error occurs.
- Returns: A promise that is guaranteed to fulfill with a value that satisfies
the predicate, or reject.
*/
func promiseWhile<T>(pred: (T) -> Bool, body: () -> Promise<T>, fail: (() -> Promise<Void>)? = nil) -> Promise<T> {
return Promise { fulfill, reject in
func loop() {
body().then { (t) -> Void in
if !pred(t) { fulfill(t) }
else {
if let fail = fail {
fail().then { loop() }
.error { reject([=10=]) }
}
else { loop() }
}
}
.error { reject([=10=]) }
}
loop()
}
}
我刚刚开始用 Swift(一种非常好的语言)编码,我正在尝试制作一个需要用户使用第三方登录服务登录的应用程序。
身份验证流程的基础如下所示:
1. 用户输入 ssn(瑞典人编号)并回车。
2. POST 到 url return 是 json blob:
{
"transactionId": "a transaction id",
"expires": "date sting in some iso format",
"autostartToken": "irrelevant for my usage"
}
3。轮询使用步骤 2 中的 transactionId
的 url。
这个 url return 是一个 json blob:
{
"state": "OUTSTANDING_TRANSACTION",
// other stuff that's uninteresting
}
一旦用户使用移动身份验证应用授予访问权限,此 url 将 return 成为一个更复杂的 json blob。 state
将变为 "COMPLETED"。
4. 从最终的 url 接收身份验证令牌,该令牌可以从步骤 3 中的 blob 获得(一旦状态为 "COMPLETED".
5.???
6. 利润!
所以我的 "problem" 是我无法真正弄清楚(以我有限的 swift 知识)如何执行第 3 步。轮询 url 直到状态为 "COMPLETED"(或者步骤 2 的过期已通过,应该会失败)。
我在 javascript 中做了一次 hacky 尝试来试用该服务,它看起来像这样:
this.postMethodThatReturnsAPromise(url, data).then(response => {
let {transactionId} = response.body;
let self = this,
max = 10,
num = 0;
return new Promise(function (resolve, reject) {
(function poll() {
self._get(`baseurl/${transactionId}`).then(res => {
let {state} = res.body;
if (state !== 'COMPLETE' && num < max) {
setTimeout(poll, 2000);
} else if (state === 'COMPLETE') {
return resolve(res);
}
});
num++;
})();
});
})
如何在 swift 3 中使用 Alamofire 和 Promisekit 执行此操作?
return Alamofire.request(url, method: .post, /* rest is omitted */).responseJSON().then { response -> String in
let d = res as! Dictionary<String, Any>
return d["transactionId"]
}.then { transactionId -> [String: Any] in
// TODO: The polling until blob contains "state" with value "COMPLETED"
// Return the final json blob as dict to the next promise handler
}.then { data in
}
这是我想出的方法,似乎工作正常。
}.then { transactionId -> Promise<PMKDataResponse> in
var dataDict: Dictionary<String, Any> = ["state": "unknown"]
return Promise { fullfill, reject in
func poll() {
// Method that fires an Alamofire get request and returns a Promise<PMKDataResponse>
self._get("baseurl/\(transactionId)").then { response -> Void in
// .toDictionary() is a extension to Data that converts a Data into a dictionary.
dataDict = response.data.toDictionary()
let state: String = dataDict["state"] as! String
if (state != "COMPLETE") {
after(interval: 2).then {
poll()
}
} else if (state == "COMPLETE") {
fullfill(response)
}
}
}
poll()
}
}
显然这不会检查交易的到期日期,但现在没问题。哦,缺少错误处理...
这是这个想法的一个很好的通用版本:
发件人:https://gist.github.com/dtartaglia/2b19e59beaf480535596
/**
Repeadetly evaluates a promise producer until a value satisfies the predicate.
`promiseWhile` produces a promise with the supplied `producer` and then waits
for it to resolve. If the resolved value satifies the predicate then the
returned promise will fulfill. Otherwise, it will produce a new promise. The
method continues to do this until the predicate is satisfied or an error occurs.
- Returns: A promise that is guaranteed to fulfill with a value that satisfies
the predicate, or reject.
*/
func promiseWhile<T>(pred: (T) -> Bool, body: () -> Promise<T>, fail: (() -> Promise<Void>)? = nil) -> Promise<T> {
return Promise { fulfill, reject in
func loop() {
body().then { (t) -> Void in
if !pred(t) { fulfill(t) }
else {
if let fail = fail {
fail().then { loop() }
.error { reject([=10=]) }
}
else { loop() }
}
}
.error { reject([=10=]) }
}
loop()
}
}