我会尽可能地解释我遇到的问题。
背景:我有一个React Native应用程序,使用Microsoft令牌基础身份验证与.Net Framework后端(Web API)通信。令牌在30分钟后过期,然后当进行下一次调用时,服务器会响应401,然后刷新令牌API被调用,新的刷新令牌被创建,应用程序使用这个新的令牌。而在等待刷新令牌时,其他调用被排队在客户端上,并且一旦令牌到达,它们将使用新的令牌被调用。
问题(谜团):问题在于有时从服务器返回状态码0。我们试图找出原因,但没有成功。我们还看到的模式是,当为刷新令牌调用时,后端删除旧令牌并生成新令牌。但是当应用程序调用新的API时,它仍然使用相同的旧令牌而不是新令牌。这并不总是发生。可能是排队的调用没有被排队吗?是否存在其他问题?
工具:我们使用四台运行IIS 10的专用服务器。我们有一个负载均衡器来平衡负载。在前端,我们使用React Native 0.64.2。我们使用react-native-ssl-pinning进行调用。
代码:以下是代码
async request( route: string, action: string, params: any = null, isJson: boolean = true, ) {
背景:我有一个React Native应用程序,使用Microsoft令牌基础身份验证与.Net Framework后端(Web API)通信。令牌在30分钟后过期,然后当进行下一次调用时,服务器会响应401,然后刷新令牌API被调用,新的刷新令牌被创建,应用程序使用这个新的令牌。而在等待刷新令牌时,其他调用被排队在客户端上,并且一旦令牌到达,它们将使用新的令牌被调用。
问题(谜团):问题在于有时从服务器返回状态码0。我们试图找出原因,但没有成功。我们还看到的模式是,当为刷新令牌调用时,后端删除旧令牌并生成新令牌。但是当应用程序调用新的API时,它仍然使用相同的旧令牌而不是新令牌。这并不总是发生。可能是排队的调用没有被排队吗?是否存在其他问题?
工具:我们使用四台运行IIS 10的专用服务器。我们有一个负载均衡器来平衡负载。在前端,我们使用React Native 0.64.2。我们使用react-native-ssl-pinning进行调用。
代码:以下是代码
async request( route: string, action: string, params: any = null, isJson: boolean = true, ) {
var options = await this.handleOption(action, params, isJson)
route = Config.API_BASE_URI + route
return new Promise(async resolve => {
try {
var response = await fetchSSLPinning(route, options)
return resolve(response)
} catch (e) {
// // console.log(e)
var originalRequest = {
route,
options,
}
var p = this.handleError(e, originalRequest)
return resolve(p)
}
})
},
处理错误的代码
异步函数handleError(error: any, originalRequest: any): Promise { const errorResponse = error
if (this.isTokenExpiredError(errorResponse)) {
return this.resetTokenAndReattemptRequest(error, originalRequest)
}
this.dispatchError(true, errorResponse.status)
return Promise.reject(error)
},
获取新的刷新令牌代码
async resetTokenAndReattemptRequest(error: any, originalRequest: any) {
try {
const resetToken = await TokenStorage.getToken()
if (!resetToken) {
return Promise.reject(error)
}
const retryOriginalRequest = new Promise(resolve => {
this.addSubscriber((accessToken: string) => {
var options = {
...originalRequest.options,
headers: {
...originalRequest.options.headers,
authorization: 'Bearer ' + accessToken,
},
}
resolve(fetchSSLPinning(originalRequest.route, options))
})
})
if (!this.isAlreadyFetchingAccessToken) {
this.isAlreadyFetchingAccessToken = true
const refreshToken = await TokenStorage.getRefreshToken()
const userName = await TokenStorage.getUsername()
const response = await AuthenticationService.refreshToken(
refreshToken,
userName,
)
if (!response) {
this.isAlreadyFetchingAccessToken = false
this.dispatchError(true, '404')
return Promise.reject(error)
}
await TokenStorage.storeTokenInfo(
response.access_token,
response.refresh_token,
response.userName,
) // save the newly refreshed token for other requests to use
const newToken = response.access_token
this.isAlreadyFetchingAccessToken = false
this.onAccessTokenFetched(newToken)
}
return retryOriginalRequest
} catch (err) {
this.isAlreadyFetchingAccessToken = false
this.dispatchError(true, err.status)
return Promise.reject(err)
}
},
运行所有订阅者的代码
onAccessTokenFetched(accessToken: string) {
// When the refresh is successful, we start retrying the requests one by one and empty the queue
this.subscribers.forEach((callback: any) => {
callback(accessToken)
})
this.subscribers = []
},
我知道想出一个解决方案很难,但是我们已经被卡住了很长时间,所以把它公开出来。
this.addSubscriber((accessToken: string)
之前,你先调用了this.onAccessTokenFetched(newToken)
。 - undefined