如何在 koa 中发送 HTTP 响应之前等待 url 回调?
Posted
技术标签:
【中文标题】如何在 koa 中发送 HTTP 响应之前等待 url 回调?【英文标题】:How to wait for a url callback before send HTTP response in koa? 【发布时间】:2018-11-16 09:44:19 【问题描述】:我有一个koa
路由器,我需要调用一个api,异步返回结果。这意味着我不能立即得到我的结果,如果没问题,api 会调用我的callback url
。但是现在我必须像同步 api 一样使用它,这意味着我必须等到回调 url 被调用。
我的路由器是这样的:
router.post("/voice", async (ctx, next) =>
// call a API here
const params =
data: "xxx",
callback_url: "http//myhost/ret_callback",
;
const req = new Request("http://xxx/api",
method: "POST",
body: JSON.stringify(params),
);
const resp = await fetch(req);
const data = await resp.json();
// data here is not the result I want, this api just return a task id, this api will call my url back
const taskid = data.taskid;
// now I want to wait here until I got "ret_callback"
// .... wait .... wait
// "ret_callback" is called now
// get the answer in "ret_callback"
ctx.body =
result: "ret_callback result here",
)
我的回调网址是这样的:
router.post("/ret_callback", async (ctx, next) =>
const params = ctx.request.body;
// taskid will tell me this answer to which question
const taskid = params.taskid;
// this is exactly what I want
const result = params.text;
ctx.body =
code: 0,
message: "success",
;
)
那么我怎样才能让这个aync
api 像sync
api 一样工作呢?
【问题讨论】:
有价值的问题。我也有同样的需求 【参考方案1】:只需将 resolve() 传递给另一个函数。例如,您可以这样做:
// use a map to save a lot of resolve()
const taskMap = new Map();
router.post("/voice", async (ctx, next) =>
// call a API here
const params =
data: "xxx",
callback_url: "http//myhost/ret_callback",
;
const req = new Request("http://xxx/api",
method: "POST",
body: JSON.stringify(params),
);
const resp = await fetch(req);
const data = await resp.json();
const result = await waitForCallback(data.taskid);
ctx.body =
result,
)
const waitForCallback = (taskId) =>
return new Promise((resolve, reject) =>
const task = ;
task.id = taskId;
task.onComplete = (data) =>
resolve(data);
;
task.onError = () =>
reject();
;
taskMap.set(task.id, task);
);
;
router.post("/ret_callback", async (ctx, next) =>
const params = ctx.request.body;
// taskid will tell me this answer to which question
const taskid = params.taskid;
// this is exactly what I want
const result = params.text;
// here you continue the waiting response
taskMap.get(taskid).onComplete(result);
// not forget to clean rubbish
taskMap.delete(taskid);
ctx.body =
code: 0,
message: "success",
; )
我没有测试它,但我认为它会起作用。
【讨论】:
【参考方案2】:这个怎么样?
router.post("/voice", async (ctx, next) =>
const params =
data: "xxx",
callback_url: "http//myhost/ret_callback",
;
const req = new Request("http://xxx/api",
method: "POST",
body: JSON.stringify(params),
);
const resp = await fetch(req);
const data = await resp.json();
// data here is not the result I want, this api just return a task id, this api will call my url back
const taskid = data.taskid;
let response = null;
try
response = await new Promise((resolve,reject)=>
//call your ret_callback and when it finish call resolve(with response) and if it fails, just reject(with error);
);
catch(err)
//errors
// get the answer in "ret_callback"
ctx.body =
result: "ret_callback result here",
);
【讨论】:
【参考方案3】:好的,首先,这不应该是您的“目标”。 NodeJS works better as ASync.
但是,让我们假设您出于某种原因仍然想要它,因此请查看 sync-request package on npm(那里有一个很大的说明,您不应该在生产环境中使用它。
但是,我希望您的意思是如何使这个 API 更简单(就像在一次调用中那样)。您仍然需要.next
或await
,但无论如何这将是一个电话。
如果是这种情况,请对此答案发表评论,我可以为您写一个我自己使用的可能方法。
【讨论】:
【参考方案4】:function getMovieTitles(substr)
let movies = [];
let fdata = (page, search, totalPage) =>
let mpath =
host: "jsonmock.hackerrank.com",
path: "/api/movies/search/?Title=" + search + "&page=" + page,
;
let raw = '';
https.get(mpath, (res) =>
res.on("data", (chunk) =>
raw += chunk;
);
res.on("end", () =>
tdata = JSON.parse(raw);
t = tdata;
totalPage(t);
);
);
fdata(1, substr, (t) =>
i = 1;
mdata = [];
for (i = 1; i <= parseInt(t.total_pages); i++)
fdata(i, substr, (t) =>
t.data.forEach((v, index, arrs) =>
movies.push(v.Title);
if (index === arrs.length - 1)
movies.sort();
if (parseInt(t.page) === parseInt(t.total_pages))
movies.forEach(v =>
console.log(v)
)
);
);
);
getMovieTitles("tom")
【讨论】:
以上是关于如何在 koa 中发送 HTTP 响应之前等待 url 回调?的主要内容,如果未能解决你的问题,请参考以下文章