node.js - Axios 每天报告“未定义”1000 次
问题描述
TLDR
我们undefined
每天从网络请求中收到数千个响应,占 Sentry 中错误事件总数的 80-90%(每天)。我已经阅读了很多关于 Axios 的“网络错误”的帖子,但我相信我们会收到如此多的错误,因为我们的服务器/节点应用程序每天都会失败很多次。
关于我们
我们每天有 1000 名活跃用户,在上午 10 点到下午 5 点之间的任何给定时间,整个应用程序上有 10 到 20 个并发用户。
我们使用 Sentry 记录在 FE 上发出的每个请求的每个错误(我们使用 try...catch 块系统,在每个 catch 块中,都有一个 Sentry 请求来报告该错误)。
我们的问题
我们每天会收到大约 4000 个错误事件(我知道非常高),但是报告了 3200 个,或者说大约 80% 是response: [undefined]
. 这使得我们无法真正找到并解决我们的用户遇到的真正错误,除非他们直接向我们报告。
我知道有很多关于 Axios 的“网络错误”的对话,因为当浏览器中出现网络错误时,Axios 无法始终如一地准确报告,但显然有些东西导致这个错误每天发生数千次用户数。
一些可能有帮助的附加信息:
- 在本地运行应用程序时偶尔会出现这种情况,但与浏览器中报告的错误没有区别。
- 我们已经尝试提高服务器的能力并告诉我们的应用程序使用更多的能力,但这甚至没有减少一点错误。
- 有时,我本地的错误会报告 CORS 问题,或者 CORS 失败。
- 这可能发生的请求没有限制,但显然,我们在更频繁的请求中看到了更多。
- 该请求似乎与浏览器或移动与桌面无关。
我希望找到什么
我相信 Axios 没有任何问题。我想知道我们的 CORS 配置是否不正确,导致错误的比例很低,或者我们的 Axios 配置不正确,或者我们后端的某些东西导致我们的服务器/系统/任何东西崩溃了很多。
任何经验或想法将不胜感激!我们被这件事困扰着。
下面看看我们的axiosConfig.js
:
// This is copied to /marketing-website/utils/api/api-service
// If it needs updated for any reason, please update /marketing-website if applicable
// Packages
import axios from 'axios'
import axiosRetry from 'axios-retry'
import { v4 as uuidv4 } from 'uuid'
// Helpers
import { getCurrentJWTToken } from './cognito'
import { CError } from './consoleMixin'
const BASE_API = async () => {
const jwtToken = await getCurrentJWTToken()
return {
headers: {
authorization: jwtToken,
indempotency: uuidv4(),
'content-type': 'application/json',
},
baseURL: process.env.VUE_APP_BASE_URL
}
}
// we don't necessarily want to hit the same base url every time, if we use other apis
// this is a place we can initialize the headers we send everywhere as well
const API = async () => {
const api = axios.create({
...await BASE_API(),
})
const userAgent = window.navigator.userAgent
// If user is on Edge or IE, return now
if (userAgent.includes('Trident') || userAgent.includes('Edge')) {
return api
}
// Breaks login on Edge/IE
api.interceptors.request.use((config) => {
config.metadata = { startTime: new Date() }
// If a controlledClient currently exists, send their information to the backend
const controlledClient = localStorage.getItem('controlledClient')
if (controlledClient) {
if (!config.params) {
config.params = { controlledClientUser: JSON.parse(controlledClient).id }
} else {
const configParams = config.params
configParams.controlledClientUser = JSON.parse(controlledClient).id
config.params = configParams
}
}
return config
}, (error) => {
this.CError(error)
return Promise.reject(error)
})
api.interceptors.response.use(
(response) => {
response.config.metadata.endTime = new Date()
response.duration = response.config.metadata.endTime - response.config.metadata.startTime
// CLog('request and time:', response.config.url, response.duration)
try {
// remove any id numbers from the end since we're grouping by API call type
const urlSplits = response.config.url.split('/');
const last = urlSplits[urlSplits.length - 1]
const url = isNaN(last)
? response.config.url
: response.config.url.split(`/${last}`)[0]
let role = 'UNAUTHENTICATED';
const user = JSON.parse(localStorage.getItem('user'))
if (user && user.employee) role = 'EMPLOYEE'
if (user && user.client) role = 'CLIENT'
if (window.ga) {
window.ga('send', {
hitType: 'timing',
timingCategory: `API REQUEST ${role} ${response.config.method.toUpperCase()}`,
timingVar: url,
timingValue: response.duration,
label: url
})
}
} catch (err) {
CError('Error with google analytics', err)
}
return response
},
(error) => {
CError('GENERAL ERROR:', error)
error.config.metadata.endTime = new Date()
error.duration = error.config.metadata.endTime - error.config.metadata.startTime
CError('AXIOS ERROR:', error.config, error.response)
try {
CError('Stringified:', JSON.stringify(error))
} catch (err) {
CError('Error with stringify error')
}
if (error.response && error.response.status === 401) {
if (
error.response.data.message.includes === 'User not found'
|| error.response.data.name === 'AuthError')
{
window.open('/login', '_self')
}
}
return Promise.reject(error)
}
);
const retryDelay = (retryNumber = 0) => {
// eslint-disable-next-line no-restricted-properties
const seconds = Math.pow(2, retryNumber) * 1000;
const randomMs = 1000 * Math.random();
return seconds + randomMs;
};
axiosRetry(api, {
retries: 3,
retryDelay,
// retry on Network Error
retryCondition: axiosRetry.isNetworkError,
});
return api
}
export default API
解决方案
推荐阅读
- ios - 自定义 UIButton .touchDragEnter 和 .touchDragExit 区域/大小?
- python - Numpy C API 整数标量
- typescript - 对具有不同操作数的 graphql 中的许多键进行可选过滤
- latex - Rounding summary statistics exported to LaTeX using esttab
- oracle - 删除 Oracle dbms_xmlschema.registerschema 添加到模式中的所有注释
- git - 行删除已完成,但没有责任归咎于
- c# - 如何从动态实例化的自定义类中更改标签的文本?
- php - 在firestore(php)中增加一个字段
- django - Django taggit how to record id of user that added tag
- c# - 如何减少我的冗余代码,创建泛型方法?