生产中的 Axios 拦截器问题
Axios interceptor issue in production
我在开发应用程序和尝试使用刷新令牌时遇到问题。我正在使用 ADFS 进行身份验证,在那里我得到一个每小时过期的 id_token 和一个持续 8 小时的刷新令牌。
在开发过程中,下面的脚本可以完美地按预期工作,并且可以连接到服务器进行刷新。
在生产环境中,它获得了新的令牌,但它从不重试原始请求。我试图找出为什么它在 webpack-dev-server 和生产环境中不同。
如有任何帮助,我们将不胜感激!
P.S。使用 Babel 预设:babel-preset-env 和 babel-preset-stage-2
axios.js
import axios from 'axios'
// Set baseURL for development and production
const baseURL = process.env.NODE_ENV === 'development' ? '//localhost:3001/api' : '/api'
// Create instance of axios with correct baseURL
const instance = axios.create({
baseURL
})
// Intercept responses
instance.interceptors.response.use((response) => {
return response
}, async (error) => {
// Pull config, status and data from the error
const { config, response: { status, data } } = error
// Pull tokens from local storage
let currentTokens = JSON.parse(localStorage.getItem('tokens')) || null
// If response errors at 401, token is still valid and we have tokens in localStorage
if(status === 401 && data.token_invalid === undefined && currentTokens && !config._retry) {
config._retry = true
try {
// Ask server for new token
const authenticate = await instance.post('/user/login', {refresh_token: currentTokens.refresh_token})
// Pull tokens and success from authenticated request
const { tokens, success } = authenticate.data
// If successful, set access_token, id_token, headers and localStorage
if(success) {
currentTokens.access_token = tokens.access_token
currentTokens.id_token = tokens.id_token
const bearer = `Bearer ${tokens.id_token}`
config.headers['Authorization'] = bearer
Object.assign(instance.defaults, {headers: {Authorization: bearer}})
localStorage.setItem('tokens', JSON.stringify(currentTokens))
// Rerun original request
return instance(config)
}
} catch (e) {
// Catch any errors
console.log(e)
return
}
} else if(data && data.token_invalid !== undefined && data.token_invalid) {
// If refresh has expired, take user to ADFS to reauthenticate
location = `${process.env.OAUTH_CLIENT_EP}?client_id=${process.env.AZURE_CLIENT_ID}&redirect_uri=${process.env.REDIRECT_URI}&resource=${process.env.REDIRECT_URI}&response_type=code`
return
} else {
// Console log all remaining errors
return
}
})
export default instance
发现问题。看来,因为我同时使用相对和绝对 urls 作为基础 URL,开发中的绝对 URL 被正确处理,但是相对 URL 是被链接到原始请求。
换句话说,在生产中发送,url 看起来像:/api/api/actual/request,它应该只是 /api/actual/request。
我通过在我的配置文件中添加 API_URL 来解决这个问题,并为开发和生产输入绝对 url 并将我的实例创建更新为以下内容。
const instance = axios.create({
baseURL: process.env.API_URL
})
感谢所有查看并试图提供帮助的人。祝大家有个愉快的一天!
我在开发应用程序和尝试使用刷新令牌时遇到问题。我正在使用 ADFS 进行身份验证,在那里我得到一个每小时过期的 id_token 和一个持续 8 小时的刷新令牌。
在开发过程中,下面的脚本可以完美地按预期工作,并且可以连接到服务器进行刷新。
在生产环境中,它获得了新的令牌,但它从不重试原始请求。我试图找出为什么它在 webpack-dev-server 和生产环境中不同。
如有任何帮助,我们将不胜感激!
P.S。使用 Babel 预设:babel-preset-env 和 babel-preset-stage-2
axios.js
import axios from 'axios'
// Set baseURL for development and production
const baseURL = process.env.NODE_ENV === 'development' ? '//localhost:3001/api' : '/api'
// Create instance of axios with correct baseURL
const instance = axios.create({
baseURL
})
// Intercept responses
instance.interceptors.response.use((response) => {
return response
}, async (error) => {
// Pull config, status and data from the error
const { config, response: { status, data } } = error
// Pull tokens from local storage
let currentTokens = JSON.parse(localStorage.getItem('tokens')) || null
// If response errors at 401, token is still valid and we have tokens in localStorage
if(status === 401 && data.token_invalid === undefined && currentTokens && !config._retry) {
config._retry = true
try {
// Ask server for new token
const authenticate = await instance.post('/user/login', {refresh_token: currentTokens.refresh_token})
// Pull tokens and success from authenticated request
const { tokens, success } = authenticate.data
// If successful, set access_token, id_token, headers and localStorage
if(success) {
currentTokens.access_token = tokens.access_token
currentTokens.id_token = tokens.id_token
const bearer = `Bearer ${tokens.id_token}`
config.headers['Authorization'] = bearer
Object.assign(instance.defaults, {headers: {Authorization: bearer}})
localStorage.setItem('tokens', JSON.stringify(currentTokens))
// Rerun original request
return instance(config)
}
} catch (e) {
// Catch any errors
console.log(e)
return
}
} else if(data && data.token_invalid !== undefined && data.token_invalid) {
// If refresh has expired, take user to ADFS to reauthenticate
location = `${process.env.OAUTH_CLIENT_EP}?client_id=${process.env.AZURE_CLIENT_ID}&redirect_uri=${process.env.REDIRECT_URI}&resource=${process.env.REDIRECT_URI}&response_type=code`
return
} else {
// Console log all remaining errors
return
}
})
export default instance
发现问题。看来,因为我同时使用相对和绝对 urls 作为基础 URL,开发中的绝对 URL 被正确处理,但是相对 URL 是被链接到原始请求。
换句话说,在生产中发送,url 看起来像:/api/api/actual/request,它应该只是 /api/actual/request。
我通过在我的配置文件中添加 API_URL 来解决这个问题,并为开发和生产输入绝对 url 并将我的实例创建更新为以下内容。
const instance = axios.create({
baseURL: process.env.API_URL
})
感谢所有查看并试图提供帮助的人。祝大家有个愉快的一天!