|
@@ -69,6 +69,14 @@ export interface SessionUser {
|
|
|
name: string;
|
|
name: string;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+interface FnResponse {
|
|
|
|
|
+ code?: number;
|
|
|
|
|
+ success?: boolean;
|
|
|
|
|
+ error?: string;
|
|
|
|
|
+ message?: string;
|
|
|
|
|
+ data?: unknown;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
@Injectable({ providedIn: 'root' })
|
|
@Injectable({ providedIn: 'root' })
|
|
|
export class TihaoProgressService {
|
|
export class TihaoProgressService {
|
|
|
get sessionToken(): string {
|
|
get sessionToken(): string {
|
|
@@ -118,27 +126,43 @@ export class TihaoProgressService {
|
|
|
|
|
|
|
|
private async callFunction<T>(action: string, params: Record<string, unknown>): Promise<T> {
|
|
private async callFunction<T>(action: string, params: Record<string, unknown>): Promise<T> {
|
|
|
const token = this.sessionToken;
|
|
const token = this.sessionToken;
|
|
|
- const resp = await fetch(`${PARSE_SERVER}/api/functions`, {
|
|
|
|
|
- method: 'POST',
|
|
|
|
|
- headers: {
|
|
|
|
|
- 'Content-Type': 'application/json',
|
|
|
|
|
- 'X-Parse-Application-Id': PARSE_APP_ID,
|
|
|
|
|
- 'X-Parse-Session-Token': token,
|
|
|
|
|
- },
|
|
|
|
|
- body: JSON.stringify({ id: PROGRESS_FN_ID, action, sessionToken: token, _ApplicationId: PARSE_APP_ID, ...params }),
|
|
|
|
|
- });
|
|
|
|
|
- const json = await resp.json().catch(() => null);
|
|
|
|
|
- if (!json) {
|
|
|
|
|
- throw new Error('NETWORK');
|
|
|
|
|
- }
|
|
|
|
|
- const code = Number(json.code || resp.status);
|
|
|
|
|
- if (code === 401) {
|
|
|
|
|
- this.logout();
|
|
|
|
|
- throw new Error('UNAUTHORIZED');
|
|
|
|
|
- }
|
|
|
|
|
- if (json.success === false || code >= 400) {
|
|
|
|
|
- throw new Error(json.error || json.message || '请求失败');
|
|
|
|
|
|
|
+ const body = JSON.stringify({ id: PROGRESS_FN_ID, action, sessionToken: token, _ApplicationId: PARSE_APP_ID, ...params });
|
|
|
|
|
+ // FMode 云函数解析登录态时偶发空响应 / fetch failed,做有限重试以稳定看板。
|
|
|
|
|
+ let lastErr: Error | null = null;
|
|
|
|
|
+ for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
|
|
|
+ let json: FnResponse | null = null;
|
|
|
|
|
+ let status = 0;
|
|
|
|
|
+ try {
|
|
|
|
|
+ const resp = await fetch(`${PARSE_SERVER}/api/functions`, {
|
|
|
|
|
+ method: 'POST',
|
|
|
|
|
+ headers: {
|
|
|
|
|
+ 'Content-Type': 'application/json',
|
|
|
|
|
+ 'X-Parse-Application-Id': PARSE_APP_ID,
|
|
|
|
|
+ 'X-Parse-Session-Token': token,
|
|
|
|
|
+ },
|
|
|
|
|
+ body,
|
|
|
|
|
+ });
|
|
|
|
|
+ status = resp.status;
|
|
|
|
|
+ json = (await resp.json().catch(() => null)) as FnResponse | null;
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ json = null;
|
|
|
|
|
+ }
|
|
|
|
|
+ const fetchFailed = json && typeof json.message === 'string' && /fetch failed/i.test(json.message);
|
|
|
|
|
+ if (!json || fetchFailed) {
|
|
|
|
|
+ lastErr = new Error('NETWORK');
|
|
|
|
|
+ await new Promise((resolve) => setTimeout(resolve, 600 * (attempt + 1)));
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ const code = Number(json.code || status);
|
|
|
|
|
+ if (code === 401) {
|
|
|
|
|
+ this.logout();
|
|
|
|
|
+ throw new Error('UNAUTHORIZED');
|
|
|
|
|
+ }
|
|
|
|
|
+ if (json.success === false || code >= 400) {
|
|
|
|
|
+ throw new Error(json.error || json.message || '请求失败');
|
|
|
|
|
+ }
|
|
|
|
|
+ return json.data as T;
|
|
|
}
|
|
}
|
|
|
- return json.data as T;
|
|
|
|
|
|
|
+ throw lastErr || new Error('NETWORK');
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|