动态决定使用哪种 Fetch 响应方法
Dynamically decide which Fetch response method to use
我使用后端 API,其中 returns 不同数据类型用于对同一端点的不同请求。虽然更合适的解决方案是统一返回的数据类型,但遗留问题、时间和缺乏测试不利于此解决方案。
我正在集中我的 call
方法,以供需要调用端点的应用程序的其他部分使用。这个call
方法实现了fetch。供参考:
export default function call<P> (method: TCallMethod, payload: P, parameter?: string): Promise<IServerResponseObject> {
const url: string = buildUrl(parameter);
const body: string | null = payload ? JSON.stringify(payload) : null;
return fetch(url, {
method,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${getAuthToken()}`
},
body
}).then(async (response) => {
let body: IServerResponseObjectBody = {
message: '',
code: ''
};
if (response) {
body = await response.json();
}
return {
status: response.status,
body
};
});
}
当我收到数据时,我正在使用 Response.json
方法对其进行解码。
if (response) {
body = await response.json();
}
问题是有时我没有收到任何数据(当用户未通过身份验证时 - 尽管这是一种边缘情况)或服务器仅以布尔值响应。
在那种情况下,json()
执行失败,因为我们没有处理 JSON 数据。
即:
FetchError: invalid json response body at http://localhost:4545/api/definition/isNameUnique/used%20name reason: Unexpected end of JSON input
我想知道是否有比嵌套 try/catches
更简洁的方法来确定从可用的方法中使用哪种解码方法:https://developer.mozilla.org/en-US/docs/Web/API/Body#Methods
这感觉像是一个潜在的解决方案:https://developer.mozilla.org/en-US/docs/Web/API/Body#Properties但是文档不是太明确并且缺乏如何使用它的示例。
我觉得您想使用 text
阅读回复,然后查看生成的文本并决定要做什么。 大致:
const text = await response.text();
if (!text) {
// no response, act accordingly
} else if (reBool.test(text)) {
// boolean response, determine whether it's true or false and act on it
} else {
// JSON response, parse it
data = JSON.parse(text);
// ...then use it
}
...其中 reBool
是用于测试服务器布尔值的正则表达式,有时 returns,例如 /^(?:true|false)$/i
.
如果响应可能有空格,您可能 trim
response.text()
的结果。
您可能还想做一些不相关的事情:
你没有检查成功的响应(这是 很多 人犯的错误,所以很多人都把它写在了我的 otherwise-anemic 小博客)。在使用 json
或 text
等之前检查 response.ok
将 async
函数作为回调传递给 then
没有多大意义。如果你打算去 async
,早点做,通过使 call
成为一个 async
函数,然后在整个 body 中使用 await
而不是混合你的比喻...
解决这些问题并折叠上面的主要答案(您需要根据需要进行调整,IServerResponseObject
需要更改或者您需要对布尔响应做一些不同的事情):
const reBool = /^(?:true|false)$/i;
export default async function call<P> (method: TCallMethod, payload: P, parameter?: string): Promise<IServerResponseObject> {
const url: string = buildUrl(parameter);
const body: string | null = payload ? JSON.stringify(payload) : null;
const response = await fetch(url, {
method,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${getAuthToken()}`
},
body
});
const {status} = response;
if (!response.ok) {
throw new Error("HTTP error " + status); // Or `return {status};` or similar, but making it an error is useful
}
const text = (await response.text()).trim();
let result = {status};
if (!text) {
// blank, act accordingly, perhaps:
result.body = null;
} else if (reBool.test(text)) {
result.body = text === "true";
} else {
result.body = JSON.parse(text);
}
return result;
}
我使用后端 API,其中 returns 不同数据类型用于对同一端点的不同请求。虽然更合适的解决方案是统一返回的数据类型,但遗留问题、时间和缺乏测试不利于此解决方案。
我正在集中我的 call
方法,以供需要调用端点的应用程序的其他部分使用。这个call
方法实现了fetch。供参考:
export default function call<P> (method: TCallMethod, payload: P, parameter?: string): Promise<IServerResponseObject> {
const url: string = buildUrl(parameter);
const body: string | null = payload ? JSON.stringify(payload) : null;
return fetch(url, {
method,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${getAuthToken()}`
},
body
}).then(async (response) => {
let body: IServerResponseObjectBody = {
message: '',
code: ''
};
if (response) {
body = await response.json();
}
return {
status: response.status,
body
};
});
}
当我收到数据时,我正在使用 Response.json
方法对其进行解码。
if (response) {
body = await response.json();
}
问题是有时我没有收到任何数据(当用户未通过身份验证时 - 尽管这是一种边缘情况)或服务器仅以布尔值响应。
在那种情况下,json()
执行失败,因为我们没有处理 JSON 数据。
即:
FetchError: invalid json response body at http://localhost:4545/api/definition/isNameUnique/used%20name reason: Unexpected end of JSON input
我想知道是否有比嵌套 try/catches
更简洁的方法来确定从可用的方法中使用哪种解码方法:https://developer.mozilla.org/en-US/docs/Web/API/Body#Methods
这感觉像是一个潜在的解决方案:https://developer.mozilla.org/en-US/docs/Web/API/Body#Properties但是文档不是太明确并且缺乏如何使用它的示例。
我觉得您想使用 text
阅读回复,然后查看生成的文本并决定要做什么。 大致:
const text = await response.text();
if (!text) {
// no response, act accordingly
} else if (reBool.test(text)) {
// boolean response, determine whether it's true or false and act on it
} else {
// JSON response, parse it
data = JSON.parse(text);
// ...then use it
}
...其中 reBool
是用于测试服务器布尔值的正则表达式,有时 returns,例如 /^(?:true|false)$/i
.
如果响应可能有空格,您可能 trim
response.text()
的结果。
您可能还想做一些不相关的事情:
你没有检查成功的响应(这是 很多 人犯的错误,所以很多人都把它写在了我的 otherwise-anemic 小博客)。在使用
json
或text
等之前检查response.ok
将
async
函数作为回调传递给then
没有多大意义。如果你打算去async
,早点做,通过使call
成为一个async
函数,然后在整个 body 中使用await
而不是混合你的比喻...
解决这些问题并折叠上面的主要答案(您需要根据需要进行调整,IServerResponseObject
需要更改或者您需要对布尔响应做一些不同的事情):
const reBool = /^(?:true|false)$/i;
export default async function call<P> (method: TCallMethod, payload: P, parameter?: string): Promise<IServerResponseObject> {
const url: string = buildUrl(parameter);
const body: string | null = payload ? JSON.stringify(payload) : null;
const response = await fetch(url, {
method,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${getAuthToken()}`
},
body
});
const {status} = response;
if (!response.ok) {
throw new Error("HTTP error " + status); // Or `return {status};` or similar, but making it an error is useful
}
const text = (await response.text()).trim();
let result = {status};
if (!text) {
// blank, act accordingly, perhaps:
result.body = null;
} else if (reBool.test(text)) {
result.body = text === "true";
} else {
result.body = JSON.parse(text);
}
return result;
}