Files
api_health/utils/user_service.js
T
2026-09-01 21:49:17 +08:00

100 lines
2.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import fetch from "node-fetch";
const USER_SERVICE_URL = process.env.USER_SERVICE_URL || "http://127.0.0.1:9010";
const CACHE_TTL = 5 * 60 * 1000; // 成功结果缓存 5 分钟
const NEGATIVE_TTL = 60 * 1000; // 无效 token 短缓存,防止打爆 user 服务
const MAX_CACHE_SIZE = 2000;
// key -> { user, expiresAt }Map 按插入序实现简易 LRU
const cache = new Map();
function cacheGet(key) {
const hit = cache.get(key);
if (!hit) return undefined;
if (Date.now() > hit.expiresAt) {
cache.delete(key);
return undefined;
}
// 重新插入以更新 LRU 顺序
cache.delete(key);
cache.set(key, hit);
return hit.user;
}
function cacheSet(key, user, ttl) {
cache.set(key, { user, expiresAt: Date.now() + ttl });
if (cache.size > MAX_CACHE_SIZE) {
cache.delete(cache.keys().next().value);
}
}
async function lookup(body) {
const res = await fetch(`${USER_SERVICE_URL}/user/userInfo`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
const data = await res.json();
return data?.data?.user || null;
}
/**
* 获取用户信息(带 5 分钟进程内缓存,token→user
*
* 注意:缓存期内登出/账户锁定/用户信息变更最多延迟 5 分钟生效
* (user 服务自身接口即时生效)
*
* @param {string} token 登录 token
* @param {string} [userId] 备用用户IDtoken 缺失或失效时的兜底路径,保持原 WS 行为)
* @returns {Promise<Object|null>} 用户信息或 null
*/
export async function getUserInfo(token, userId) {
if (!token && !userId) return null;
// 1. token 路径(带缓存)
if (token) {
const key = `tk:${token}`;
const cached = cacheGet(key);
if (cached !== undefined) return cached;
try {
const user = await lookup({ token });
if (user) {
cacheSet(key, user, CACHE_TTL);
return user;
}
// 无效 token 短缓存,保护 user 服务
cacheSet(key, null, NEGATIVE_TTL);
} catch (err) {
// 网络异常不缓存,走 userId 兜底
console.error("getUserByToken error:", err.message);
}
}
// 2. userId 兜底路径
if (userId) {
const key = `uid:${userId}`;
const cached = cacheGet(key);
if (cached !== undefined) return cached;
try {
const user = await lookup({ userId });
if (user) {
cacheSet(key, user, CACHE_TTL);
return user;
}
} catch (err) {
console.error("getUserById error:", err.message);
}
}
return null;
}
/**
* 仅按 token 获取用户信息(REST 鉴权用,无 userId 兜底)
*/
export async function getUserByToken(token) {
return getUserInfo(token, null);
}