654 字
3 分钟
Steam 家庭共享库预览 - 服务端设计与实现
在这篇文章中,我将介绍如何设计和实现一个基于 Node.js 和 Express 框架的服务端项目,提供 Steam 家庭共享库的预览功能。我们将聚焦于一个名为 gamers 的接口,该接口接收 ids 参数,并返回对应的游戏信息。
技术栈选择
在构建服务端项目时,选择合适的技术栈是成功的关键。对于本项目,我们选择了 Node.js 和 Express 框架。选择这两者的原因如下:
- Node.js:Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时,具有非阻塞、事件驱动的特点,非常适合构建高并发的应用程序。
- Express:Express 是一个快速、简洁的 Node.js Web 应用框架,提供了一系列强大的功能来帮助开发者快速构建 Web 应用和 API。
接口设计
主要用到的 Steam Web API 接口如下
• 获取用户信息: http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/
• 获取用户拥有的游戏: http://api.steampowered.com/IPlayerService/GetOwnedGames/v0001/
• 获取游戏详细信息: http://store.steampowered.com/api/appdetails
接口实现
app.post('/get/gamers', async (req, res) => {
try {
const { ids, key: reqKey = '' } = req.body;
if (!ids || ids?.length === 0) {
res.send({
code: 400,
data: null,
msg: '请输入用户 id',
success: false,
});
}
const key = reqKey || await getKey();
if (!key) {
res.send({
code: 500,
data: null,
msg: '无可用key',
success: false,
});
}
const resPlayerSummaries = await service({
url: '/ISteamUser/GetPlayerSummaries/v0002/',
params: {
steamids: ids.join(','),
format: 'json',
key,
},
instance: 'IPlayerService',
method: 'get',
}).then(res => {
if (res.response.players) {
return res.response.players;
}
return [];
});
if (resPlayerSummaries.length === 0) {
res.send({
code: 400,
data: null,
msg: '输入的用户 id 均无效',
success: false,
})
}
const resAllGames= await Promise.allSettled(resPlayerSummaries.map(player => {
if (player.communityvisibilitystate === 1) {
return Promise.resolve({games: [], steamid: player.steamid});
}
return service({
url: '/IPlayerService/GetOwnedGames/v0001/',
params: {
steamid: player.steamid, // 76561198391051438
format: 'json',
key,
},
instance: 'IPlayerService',
}).then(res => {
if (res.response?.games) {
return {games: res.response.games, steamid: player.steamid};
}
return {games: [], steamid: player.steamid};
})
})).then(res => {
return res.map(res => res.value);
});
const allGamesIds = [...new Set(...[resAllGames.map(res => res?.games.map(game => game.appid))].map(ids => ids.flat()))];
const resGames = await Promise.allSettled(allGamesIds.map(appid => {
return service({
url: '/api/appdetails?appids',
params: {
appids: appid,
l: 'schinese',
cc: 'cn',
format: 'json',
filters: 'basic,price_overview,categories',
key,
},
instance: 'Storefront',
}).then(res => {
const data = Object.values(res)[0];
if (data.success) {
return data.data;
}
return {
steam_appid: appid,
success: false,
};
}).catch(err => {
return {
steam_appid: appid,
success: false,
};
});
}));
const successGames = resGames.filter(game => (game.value?.success ?? true));
const failGames = resGames.filter(game => !(game.value?.success ?? true));
const result = [];
ids.forEach((id, index) => {
const cur = resPlayerSummaries.find(player => player.steamid === id);
if (!cur) {
return;
}
if (cur.communityvisibilitystate === 1) {
result.push({
isPublic: false,
user: cur,
stock: [],
failGameId: [],
});
return;
}
const curUserGameIds = resAllGames.find(res => res?.steamid === id)?.games.map(game => game.appid);
result.push({
isPublic: true,
user: cur,
stock: successGames.filter(game => curUserGameIds?.includes(game.value.steam_appid)).map(game => game.value),
failGameId: failGames.filter(game => curUserGameIds?.includes(game.value.steam_appid)).map(game => game.value.steam_appid),
});
});
res.send({
code: 200,
data: result,
msg: 'success',
success: true,
});
} catch (e) {
console.log(e);
res.send({
code: 500,
msg: e === '无可用key' ? e : '服务器错误',
success: false,
});
}
});
接口测试
- 无入参
- 随机输入的 steamid
- 真实存在的 steamid
Steam 家庭共享库预览 - 服务端设计与实现
https://www.promises.top/posts/front/steamshared/server-side-design-and-implementation/