我目前正在开发 NextJS 应用程序(应用程序路由器),并与 Clerk 一起使用他们的
@clerk/nextjs
(4.29.7) 包进行身份验证。
一切正常,直到互联网连接中断。由于 Clerk 使用非常短暂的访问令牌,因此它大约每分钟请求一个新令牌。显然,一旦互联网连接丢失,下一个请求就会失败并首先导致
clerk.browser.js:2
POST https://**********.clerk.accounts.dev/v1/client/sessions/sess_2cy4a…9vLkBPD4GVFExWN5Dc-nMoU8VxlNWAbb4w3X6ELJ7xw7OIG5X68F6Rm86nnbnzgrNQctoOKnFA net::ERR_INTERNET_DISCONNECTED
导致以下错误:
clerk.browser.js:2
Uncaught (in promise) Error: ClerkJS: Token refresh failed (error='Cannot read properties of null (reading 'jwt')')
at p (clerk.browser.js:2:74485)
at h.handleGetTokenError (clerk.browser.js:2:192240)
at h.refreshSessionToken (clerk.browser.js:2:191543)
at async Object.acquireLockAndRun (clerk.browser.js:2:140446)
例如,当您在应用程序上关闭笔记本电脑并重新打开它以稍后恢复会话时,就会出现这种情况。让应用程序中断而不尝试重定向以登录或重新尝试获取新令牌是相当不幸的。
我试图找到一种方法来捕获并处理该错误,或者通过在离线时停止请求来首先阻止它,但我没有找到任何方法来做到这一点。文档中似乎没有任何内容,我很惊讶到目前为止似乎没有人为此苦苦挣扎。
如果有任何关于如何处理这个问题的想法或见解,我将不胜感激。 提前致谢! 🙏
直接用错误处理来处理错误是一个很好的做法。您可以通过捕获错误并实施重试机制或替代响应来自定义应用程序在令牌刷新由于丢失互联网连接而失败时的反应方式。具体方法如下:
使用自定义错误处理程序封装 Clerk 的令牌刷新逻辑:您可以通过在令牌刷新失败时添加错误处理来扩展 Clerk 的默认行为。
重试逻辑或回退处理:当令牌刷新失败时,您可以选择延迟后重试请求或将用户重定向到不同的页面(例如“重新连接”页面)。
这是实现此方法的示例:
import { ClerkProvider } from '@clerk/nextjs';
import { useEffect } from 'react';
export default function MyApp({ Component, pageProps }) {
useEffect(() => {
// Hook into Clerk's error handling
const originalHandleError = Clerk.onError;
Clerk.onError = async (error) => {
console.error('ClerkJS error:', error);
// Custom error handling
if (error.message.includes('Token refresh failed')) {
console.warn('Token refresh failed, possibly due to a lost connection.');
// Check if the browser is offline
if (!navigator.onLine) {
console.warn('Browser is offline. Will retry once back online.');
// Wait for the user to come back online
await new Promise((resolve) => {
window.addEventListener('online', resolve, { once: true });
});
console.log('Back online. Retrying token refresh.');
// Retry token refresh here
try {
await Clerk.client.sessions.refresh();
console.log('Token refresh successful after reconnecting.');
} catch (refreshError) {
console.error('Token refresh failed after reconnecting:', refreshError);
// Optionally, you can handle further failure (e.g., log out the user)
}
} else {
// Handle other token refresh errors here
console.warn('Other token refresh error occurred. Consider redirecting to sign-in.');
}
}
// Call the original error handler
if (originalHandleError) {
originalHandleError(error);
}
};
return () => {
// Clean up the error handler on component unmount
Clerk.onError = originalHandleError;
};
}, []);
return (
<ClerkProvider>
<Component {...pageProps} />
</ClerkProvider>
);
}