在节点服务器和前端处理 JSON 响应



我有一个发送 JSON 响应的节点服务器,但我为什么必须在前端再次执行res.json()才能使我的响应正常工作?

另外,在前端处理提取的理想约定是什么?比如我应该如何构建我的异步/等待函数?

服务器.js

const express = require('express')
const path = require('path')
const bodyParser = require('body-parser')
const fetch = require('node-fetch')
const app = express()
const port = process.env.PORT || 5000
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true }))
const TRANSLINK_TOKEN = 'j2bXKzENILvyoxlZ399I'
const TRANSLINK_URL = 'http://api.translink.ca/rttiapi/v1/buses?apikey='
// API routes
app.get('/buses/location', async (req, res) => {
const apiURL = `${TRANSLINK_URL}${TRANSLINK_TOKEN}`
try {
const response = await fetch(apiURL, { headers: { 'Accept': 'application/json' }})
const jsonResponse = await response.json()
res.send(jsonResponse)
}
catch (e){
console.log(e)
}
})
app.listen(port, () => console.log(`Listening on port ${port}`))

应用.js

fetchLocation = async () => {
let locationURL = "/buses/location"
fetch(locationURL)
.then(res => {
if (res.ok) {
res.json()
.then( (result) => {
this.setState({
active_vehicles: result
})
})
}
})
}

你必须执行res.json,因为HTTP响应的主体只是一个字符串。代码无法知道字符串的格式,除非你告诉它,这就是res.json的用武之地:你告诉代码将字符串响应解析为JSON并返回结果对象。

至于结构,如果你已经在前端使用异步函数,你也应该在那里使用 await,以帮助扁平化代码:

fetchLocation = async () => {
let locationURL = "/buses/location";
const res = await fetch(locationURL);
if (res.ok) {
const result = await res.json();
this.setState({
active_vehicles: result
});
}
};

这只是 FE 中如何实现fetch的本质。它不会自动解析对 json 的响应。

请参阅:https://developer.mozilla.org/en-US/docs/Web/API/Body/json

您可以使用为您处理内容类型的第三方库(如axios( - 或者如果您确信从服务器返回的所有内容都将有效json,则可以编写一个简单的函数来包装fetch

顺便说一句,由于您已经在使用async您应该使用await而不是then/catch

fetchLocation = async () => {
try {
let locationURL = "/buses/location"
const response = await fetch(locationURL);
if (response.ok) {
const result = await response.json();
this.setState({ active_vehicles: result });
} else {
// you probably should handle cases when response is not ok - fetch doesn't throw errors for 4xx, 5xx, 3xx codes.
}
} catch(e) {
// handle request failure here.
}
}

有了fetch,每次发出HTTP请求时都需要使用res.json()

您的服务器正在向api.translink.ca发出GET请求。调用res.json()时,它会处理在系统较低级别调用的异步任务,以实际接收和读取数据。

您的客户也在发出GET请求,但不是向api.translink.ca发出请求,而是向您的主机发出请求。如果您在自己的计算机上运行服务器,那将是localhost的,并且完整的URL是localhost/buses/location。您正在发出另一个GET请求的事实就是您需要再次致电res.json()的原因。

对于你的第二个问题,惯例是一个偏好问题。

await只是语法糖,以避免所谓的回调地狱。

只需将你从承诺中获得的最终值解析为你期望的变量,并尽量保持你的代码可读性和整洁性。

例如

更新代码:

fetchLocation = async () => {
let locationURL = "/buses/location"
let res = await fetch(locationURL);
if (res.ok) {
let result = await res.json();
this.setState({ active_vehicles: result });
}
};

最新更新