feat(api): migrate HTTP layer to ofetch with token interceptor
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* 设备 ID 工具类
|
||||
*
|
||||
* 使用 fingerprintjs 生成客户端设备指纹。
|
||||
* 原始 Dart: lib/data/services/device_id_service_impl.dart
|
||||
*
|
||||
* 注:仅在浏览器环境可用;SSR/Server Components 中调用会抛错。
|
||||
*/
|
||||
import { authStorage } from "../../storage/auth_storage";
|
||||
|
||||
export class DeviceIdentifier {
|
||||
private cachedId: string | null = null;
|
||||
private initPromise: Promise<string> | null = null;
|
||||
|
||||
/**
|
||||
* 获取或生成设备 ID
|
||||
*
|
||||
* 优先级:内存缓存 → localStorage 缓存 → fingerprintjs 生成
|
||||
* 并发安全:多个并发调用会共享同一个 fingerprintjs 加载 Promise
|
||||
*/
|
||||
async getDeviceId(): Promise<string> {
|
||||
if (this.cachedId) return this.cachedId;
|
||||
if (this.initPromise) return this.initPromise;
|
||||
|
||||
this.initPromise = this.initialize();
|
||||
this.cachedId = await this.initPromise;
|
||||
return this.cachedId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置缓存与持久化(用于测试或多账号切换)
|
||||
*/
|
||||
reset(): void {
|
||||
this.cachedId = null;
|
||||
this.initPromise = null;
|
||||
authStorage.removeDeviceId();
|
||||
}
|
||||
|
||||
private async initialize(): Promise<string> {
|
||||
// 1. 优先从 localStorage 读取
|
||||
const stored = authStorage.getDeviceId();
|
||||
if (stored) return stored;
|
||||
|
||||
// 2. SSR/Node 环境守卫:调用方必须保证在浏览器中调用
|
||||
if (typeof window === "undefined") {
|
||||
throw new Error(
|
||||
"DeviceIdentifier only works in browser environment. " +
|
||||
"Call getDeviceId() from a Client Component or browser code."
|
||||
);
|
||||
}
|
||||
|
||||
// 3. 动态加载 fingerprintjs(避免 Next.js SSR 打包分析时执行)
|
||||
const { load } = await import("@fingerprintjs/fingerprintjs");
|
||||
const fp = await load();
|
||||
const result = await fp.get();
|
||||
|
||||
// 4. 持久化
|
||||
authStorage.setDeviceId(result.visitorId);
|
||||
return result.visitorId;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 全局单例
|
||||
*/
|
||||
export const deviceIdentifier = new DeviceIdentifier();
|
||||
Reference in New Issue
Block a user