hmjz100/LinkSwift · error · Error
[迅雷云盘] 获取令牌失败
Error message
[迅雷云盘] 获取令牌失败
What it means
Wrapper error in 迅雷云盘 (Xunlei Cloud) getFileUrl: before fetching a file's download URL it calls this.getToken(false, false) to obtain the in-memory token. If that call rejects with a non-Error value, it is re-thrown as '[迅雷云盘] 获取令牌失败'. The real reason (expired token, failed refresh) is in the original rejection value.
Source
Thrown at (改)网盘直链下载助手.user.js:7731
cap = { token: res.captcha_token, expires_at: new Date(timestamp + res.expires_in * 1000).toString() };
base.setStorage(capKey, cap);
} else {
throw new Error(`错误:<br/>令牌刷新失败,${res?.error_description || res?.error || "未知错误"}`);
}
} else if (!creds || !cap || !clientId || !deviceId) {
throw new Error(`错误:<br/>请先登录网盘后再获取文件呢~`);
}
return { credentials: creds, captcha: cap, device_id: deviceId };
});
},
async getFileUrl(item, index, isRetry = false) {
if (item.downloadUrl) return { index, downloadUrl: item.downloadUrl };
// 获取当前内存中的 token
const token = await this.getToken(false, false).catch(e => {
if (e instanceof Error) throw e;
throw new Error(e?.message || e || "[迅雷云盘] 获取令牌失败");
});
const res = await base.get(config.$xunlei.api.getLink + item.id, {
"Authorization": `${token.credentials?.token_type} ${token.credentials?.access_token}`,
"Content-Type": "application/json",
"X-Captcha-Token": token.captcha.token,
"X-Device-Id": token.device_id
});
if (res.web_content_link) {
return { index, downloadUrl: res.web_content_link };
} else {
// 令牌过期
if (res.error_code == 9) {
// 递归重试一次,isRetry=true 防止死循环
if (!isRetry) {
await this.getToken(true, false);
return await this.getFileUrl(item, index, true);
View on GitHub (pinned to 417ea5e28a)
Solutions
- Reload the cloud drive page to rebuild the in-memory token state, then retry
- Log in to Xunlei Cloud again in the userscript to refresh credentials
- Check the console for the original rejection payload to identify the true refresh failure
- Fix the token source so it throws Error instances with meaningful messages instead of raw objects
Example fix
// before
tokenPromise.catch(e => { throw e; });
// after
tokenPromise.catch(e => { throw e instanceof Error ? e : new Error("获取令牌失败: " + JSON.stringify(e)); }); Defensive patterns
Strategy: retry
Validate before calling
const token = getCachedXunleiToken();
if (!token || token.expiresAt <= Date.now()) { await refreshToken(); } Type guard
function hasValidToken(t) { return Boolean(t?.credentials?.access_token && t?.captcha?.token); } Try / catch
try { return await getFileUrl(item, i); } catch (e) { if (e.message.includes('获取令牌失败')) { await refreshToken(); return getFileUrl(item, i); } throw e; } Prevention
- Proactively refresh tokens before expiry
- Reload long-lived tabs periodically
- Log raw rejection payloads
- Rate-limit token refresh calls
When it happens
Trigger: getFileUrl(item, index) called for a file without a cached downloadUrl; getToken(false, false) rejects with a non-Error — usually because the cached access token expired and the silent refresh path returned a non-Error rejection.
Common situations: Long-lived browser tab where the Xunlei access token expired mid-session; Xunlei API returning a JSON error object (not an Error) on refresh; rate limiting on the token endpoint; user logged out on another device invalidating the token.
Related errors
- [迅雷云盘] 获取文件 URL 失败
- 9019
- AccessTokenInvalid
- [天翼云盘] 获取文件 URL 失败
- 错误:<br/>令牌刷新失败,${res?.error_description || res?.error || "未知
AI-assisted analysis of hmjz100/LinkSwift@417ea5e28a (2026-09-02).
Data as JSON: /api/errors/ae15f4925cc9e954.
Report an issue: GitHub.