Promise 链接访问数据时避免意外结果的指南(Node-fetch)
2024-04-01 00:35:53
如何通过 Promise 链接访问数据(Node-fetch)
作为开发人员,在处理异步操作时经常需要使用 Promise。在 Node.js 中,我们可以使用 node-fetch
库来发送网络请求并处理响应。然而,有时在处理嵌套的 Promise 链时,我们可能会遇到意外的问题。
问题
设想这样一个场景:我们要从服务器获取一个用户对象,该对象包含姓名、年龄、性别等信息。我们通过 Promise 链来实现,首先获取一个登录令牌,然后使用令牌获取用户数据。但是,当我们尝试访问用户对象时,却得到了一个意外的结果。
以下是如何重现该问题的代码片段:
const fetch = require('node-fetch');
fetch('http://34.245.86.200:9084/api/auth/login', {
method: 'POST',
body: JSON.stringify({
Identifier: '17123456788',
Password: 'bambam'
}),
headers: {
'Content-type': 'application/json'
}
}).then(response => {
return response.json()
}).then(
data => {
const header = {
'Authorization': 'Bearer ' + data.token
}
return fetch('http://34.245.86.200:9085/api/user', {
method: 'GET',
headers: header
})
}).then(msg => {
console.log(msg.body)
})
期待的结果是:
{
"title": null,
"firstName": "Kay",
"lastName": "Atom",
"primaryPhoneNumber": "+1 712-345-6788",
"fullName": "Kay Atom",
"sex": null,
"email": "[email protected]",
"image": null,
}
然而,实际的控制台输出却令人惊讶:
{
token:
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJrYXlAYmFtLmNvbSIsImVtYWlsIjoia2F5QGJhbS5jb20iLCJnaXZlbl9uYW1lIjoiS2F5Iiwic2lkIjoiMzQ0MDM1ODM5NGZmNGUxNzhkMmJhNzcxNmVjYjM3YTgiLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3JvbGUiOiJQYXRpZW50IiwiYXV0aF90aW1lIjoiMDcvMDcvMjAyMCAxNzowOTo1MCIsImV4cCI6MTU5NDE0ODk5MCwiaXNzIjoiTGVpbGFQcm9qZWN0IiwiYXVkIjoiTGVpbGFQcm9qZWN0In0.DHuxUY77Jrsd_wBOrcZ-cmqvE8nh5I3TzpLIrRUuuhI',
message: 'Successfully Logged In [email protected]'
}
PassThrough {
_readableState: ReadableState {
objectMode: false,
highWaterMark: 16384,
buffer: BufferList {
head: [Object],
tail: [Object],
length: 1
},
length: 372,
pipes: [],
flowing: null,
ended: false,
endEmitted: false,
reading: true,
sync: false,
needReadable: true,
emittedReadable: false,
readableListening: false,
resumeScheduled: false,
errorEmitted: false,
emitClose: true,
autoDestroy: true,
destroyed: false,
errored: false,
closed: false,
closeEmitted: false,
defaultEncoding: 'utf8',
awaitDrainWriters: null,
multiAwaitDrain: false,
readingMore: false,
decoder: null,
encoding: null,
[Symbol(kPaused)]: null
},
_events: [Object: null prototype]{
prefinish: [Function: prefinish],
unpipe: [Function: onunpipe],
error: [[Function: onerror], [Function(anonymous)]],
close: [Function: bound onceWrapper]{
listener: [Function: onclose]
},
finish: [Function: bound onceWrapper]{
listener: [Function: onfinish]
}
``
},
_eventsCount: 5,
_maxListeners: undefined,
_writableState: WritableState {
objectMode: false,
highWaterMark: 16384,
finalCalled: false,
needDrain: false,
ending: false,
ended: false,
finished: false,
destroyed: false,
decodeStrings: true,
defaultEncoding: 'utf8',
length: 0,
writing: false,
corked: 0,
sync: false,
bufferProcessing: false,
onwrite: [Function: bound onwrite],
writecb: null,
writelen: 0,
afterWriteTickInfo: null,
buffered: [],
bufferedIndex: 0,
allBuffers: true,
allNoop: true,
pendingcb: 0,
prefinished: false,
errorEmitted: false,
emitClose: true,
autoDestroy: true,
errored: false,
closed: false
},
allowHalfOpen: true,
_transformState: {
afterTransform: [Function: bound afterTransform],
needTransform: true,
transforming: false,
writecb: null,
writechunk: null,
writeencoding: 'buffer'
},
[Symbol(kCapture)]: false
解决方法
问题的根源在于我们如何处理第二个 fetch
请求的响应。在原始代码中,我们使用 console.log(msg.body)
记录响应正文。虽然这可以显示响应的原始正文,但它不会将正文解析为 JSON 对象。
为了正确解析响应正文并访问用户对象,我们需要使用 response.json()
方法。以下是更新后的代码片段:
const fetch = require('node-fetch');
fetch('http://34.245.86.200:9084/api/auth/login', {
method: 'POST',
body: JSON.stringify({
Identifier: '17123456788',
Password: 'bambam'
}),
headers: {
'Content-type': 'application/json'
}
}).then(response => {
return response.json()
}).then(
data => {
const header = {
'Authorization': 'Bearer ' + data.token
}
return fetch('http://34.245.86.200:9085/api/user', {
method: 'GET',
headers: header
})
}).then(response => response.json()).then(user => {
console.log(user)
})
通过这种方式,我们可以正确解析响应正文并访问用户对象。
常见问题解答
1. 为什么使用 Promise 链接来访问数据?
Promise 链接是一种处理异步操作的有效方式,因为它允许我们以顺序方式执行任务,并处理每个任务的结果。
2. 如何链式 Promise?
可以通过使用 then()
方法来链式 Promise。then()
方法接受一个回调函数,该回调函数将前一个 Promise 的结果作为输入,并返回一个新的 Promise。
3. 为什么需要解析响应正文?
HTTP 响应的正文通常是未解析的文本。为了访问响应正文中的数据,我们需要将其解析为 JSON、XML 或其他格式。
4. node-fetch
库有什么好处?
node-fetch
库是一个 Node.js 库,它提供了类似于浏览器 fetch
API 的功能。它易于使用,并且支持各种选项,例如超时和重试。
5. 如何避免类似的问题?
在处理异步操作时,需要注意以下事项:
- 始终确保正确解析响应正文。
- 处理 Promise 链时要小心,尤其是嵌套 Promise 链。
- 使用调试工具来帮助识别和解决问题。