在nodejs中不使用任何第三方模块的情况下,实现对错误/条件重试的正确方法是什么?
我不确定如何针对错误调用相同的函数,以及如何将原始回调/数据传递给新调用的函数?
我需要销毁/结束插座吗?
我尝试查找示例,但只找到了似乎无效的第三方模块和http.get示例的引用。一个如何测试呢? 我尝试以下操作均未成功:
async pingApi(cb) {
let options = {
"method":"post",
"path": `/API/pingAPI?${this.auth}`, /ect do I reference this path?
}
};
let request = await http.request(options, (response) => {
let body = new Buffer(0);
response.on('data', (chunk) => {
body = Buffer.concat([body, chunk]);
});
response.on('end', function () {
if (this.complete) {
let decoded = new Buffer(body, 'base64').toString('utf8')
let json = JSON.parse(decoded);
if (json.result != 'OK') {
setTimeout(pingApi, 1000); //cant pass callback
} else {
cb(null, json.result) //works
}
}
});
})
request.end(); //does the socket need to be closed if retry is this function?
}
向我指出正确的方向或批评的任何帮助将不胜感激,因为我认为这对我来说是非常重要的学习曲线。
先谢谢您
答案 0 :(得分:2)
我不确定如何针对错误调用相同的函数,以及如何将原始回调/数据传递给新调用的函数?
我不确定您函数中的其他所有内容是否正确,但是您可以通过更改以下内容来解决所要求的递归:
setTimeout(pingApi, 1000); //cant pass callback
对此:
setTimeout(() => {
this.pingApi(cb);
}, 1000);
这里没有显示整个上下文,但是如果pingApi()
是一种方法,那么您还需要跟踪this
的值,以便可以调用this.pingApi(db)
。您可以使用以下箭头函数回调保留this
的值:
response.on('end', () => { ... });
我注意到这里还有其他东西:
await http.request()
。 http.request()
不会返回承诺,因此将await
与它一起使用并没有任何用处。await
,就没有理由将函数声明为async
,因为没有人使用它的返回承诺。if (this.complete)
是做什么的。由于它位于常规函数回调中,因此this
的值将不是您的pingApi对象。您通常应该将this
保存在范围内的更高位置const self = this
,或者内部需要将所有回调都用作箭头函数,以便保留this
的值。try/catch
放在JSON.parse()
周围,因为如果输入不是完美的JSON,它可能会抛出。我需要销毁/结束插座吗?
否,请求结束后会自动发生。
如何对此进行测试?
您必须在服务器中创建一个测试路由,该路由返回前几个请求的错误情况,然后返回成功的响应,并查看您的代码是否可以使用该路由。
这是尝试进行代码修复(未经测试):
const maxRetries = 10;
pingApi(cb, cnt = 0) {
let options = {
"method":"post",
"path": `/API/pingAPI?${this.auth}`, // ect do I reference this path?
};
let request = http.request(options, (response) => {
let body = new Buffer(0);
response.on('data', (chunk) => {
body = Buffer.concat([body, chunk]);
});
response.on('end', () => {
if (this.complete) {
let decoded = new Buffer(body, 'base64').toString('utf8')
try {
let json = JSON.parse(decoded);
if (json.result != 'OK') {
if (cnt < maxRetries)
setTimeout(() => {
this.pingApi(cb, ++cnt);
}, 1000);
} else {
cb(new Error("Exceeded maxRetries with error on pingApi()"));
}
} else {
cb(null, json.result) //works
}
} catch(e) {
// illegal JSON encountered
cb(e);
}
}
});
})
request.end();
}
有关此代码的尚待解决的问题:
this.complete
在做什么,this
应该在引用什么?request.write()
发送POST请求的正文?我知道您不要求任何外部模块,但是我这样做的首选方法是使用Promise,并在http.request()
周围使用请求-承诺包装器,因为它为您处理了很多此代码(检查为您提供response.status,为您解析JSON,使用Promise接口等)。您可以看到代码更简洁:
const rp = require('request-promise');
const maxRetries = 5;
pingApi(cnt = 0) {
let options = {
method: "post",
url: `http://somedomain.com/API/pingAPI?${this.auth}`,
json: true
};
return rp(options).then(result => {
if (result.result === "OK") {
return result;
} else {
throw "try again"; // advance to .catch handler
}
}).catch(err => {
if (cnt < maxRetries) {
return pingApi(++cnt);
} else {
throw new Error("pingApi failed after maxRetries")
}
});
}
然后,使用示例:
pingApi().then(result => {
console.log(result);
}).catch(err => {
console.log(err);
})
答案 1 :(得分:1)
您对核心节点服务器使用async / await引起了我的兴趣,我已经尝试了尽可能多地使用这种新的异步功能。
这就是我的结局:https://runkit.com/marzelin/pified-ping
const pify = require("util").promisify;
const http = require("http");
const hostname = "jsonplaceholder.typicode.com";
const failEndpoint = "/todos/2";
const goodEndpoint = "/todos/4";
let options = {
method: "get",
path: `${failEndpoint}`,
hostname
};
async function ping(tries = 0) {
return new Promise((res) => {
const req = http.request(options, async (response) => {
let body = new Buffer(0);
response.on("data", (chunk) => {
body = Buffer.concat([body, chunk]);
})
const on = pify(response.on.bind(response));
await on("end");
let decoded = new Buffer(body, 'base64').toString('utf8')
let json = JSON.parse(decoded);
if (json.completed) {
return res("all good");
}
if (tries < 3) {
console.log(`retrying ${tries + 1} time`);
return res(ping(tries + 1));
}
return res("failed");
})
req.on('error', (e) => {
console.error(`problem with request: ${e.message}`);
});
// write data to request body
req.end();
})
}
const status = await ping();
"status: " + status