如何在Koa+TypeScript中将回调数据传入ctx.body的data字段?
解决Koa路由中异步回调数据传递的问题
当然可以把回调里拿到的对象存入变量再放到ctx.body的data键里!不过你现在的代码里有个核心问题——request库的回调是异步执行的,你写的ctx.body = { data: body }会在回调函数触发之前就运行,所以根本拿不到回调里的body数据。
为什么会这样?
Node.js是异步非阻塞的,当你调用request(options, callback)时,这个函数会立刻返回,然后继续执行后面的ctx.body代码;而回调函数要等HTTP请求完成后才会触发。这就导致你设置ctx.body的时候,回调里的body还没被赋值,自然拿不到数据。
正确的解决方式:用Promise+await处理异步请求
Koa的路由支持async/await,所以最好的做法是把request的回调转换成Promise,这样就能用await等待请求完成,确保拿到数据后再设置ctx.body。
方案1:使用request-promise-native(推荐)
这是request库的Promise封装版本,直接支持await,用起来很方便。
首先安装依赖:
npm install request-promise-native @types/request-promise-native --save
然后修改你的路由代码:
import * as rp from 'request-promise-native'; router.post('/api/send_otp', async (ctx: Koa.Context, next: () => Promise<any>) => { const phone = ctx.request.body.phone; if (!phone) { ctx.body = { message: "Please enter phone number" }; return; // 记得return,避免执行后面的代码 } const options = { url: '', // 替换成你的实际请求URL method: 'POST', auth: { user: '', // 替换成实际用户名 pass: '' // 替换成实际密码 }, json: true, // 自动把返回的JSON解析成对象,无需手动JSON.parse resolveWithFullResponse: false // 只返回body,不需要整个response对象 }; try { // 用await等待请求完成,把结果存入变量 const responseBody = await rp(options); console.log(responseBody); // 控制台依然能看到数据 // 现在可以把变量传入ctx.body了 ctx.body = { data: responseBody }; } catch (error) { // 处理请求失败的情况 console.log('error', error); ctx.body = { message: "Failed to send OTP", error: error.message }; ctx.status = 500; // 设置合适的HTTP错误状态码 } });
方案2:手动封装Promise(无需额外依赖)
如果你不想安装新依赖,可以自己把request包装成Promise:
import * as request from 'request'; // 封装一个Promise版本的request工具函数 const requestPromise = (options: request.Options) => { return new Promise((resolve, reject) => { request(options, (error, response, body) => { if (error) { reject(error); } else if (response.statusCode !== 200) { // 可以根据状态码判断请求是否成功 reject(new Error(`Request failed with status ${response.statusCode}`)); } else { // 如果返回的是JSON字符串,手动解析成对象 const parsedBody = typeof body === 'string' ? JSON.parse(body) : body; resolve(parsedBody); } }); }); }; // 路由代码 router.post('/api/send_otp', async (ctx: Koa.Context, next: () => Promise<any>) => { const phone = ctx.request.body.phone; if (!phone) { ctx.body = { message: "Please enter phone number" }; return; } const options = { url: '', method: 'POST', auth: { user: '', pass: '' } }; try { const responseBody = await requestPromise(options); console.log(responseBody); ctx.body = { data: responseBody }; } catch (error) { console.log('error', error); ctx.body = { message: "Failed to send OTP", error: error.message }; ctx.status = 500; } });
总结
完全可以把回调里的对象存入变量再传到ctx.body,但必须解决异步时序问题。用Promise+await的方式既符合Koa的异步编程风格,又能避免回调地狱,还能保证数据正确获取后再返回给客户端。
内容的提问来源于stack exchange,提问作者user12561026
相关产品推荐
相关产品推荐

