当前位置: 首页 > news >正文

前端捕获异常的全面场景及方法

前端捕获异常的全面场景及方法

  • 异常处理的核心方法论
  • react的ErrorBoundary
    • 原理
    • 实现细节
    • 使用
    • 注意事项
      • 局限性: 如react的ErrorBoundary 只能捕获子组件的 render 错误,具备无法处理的情况:
  • Vue组件render异常场景及深度解析
    • 常见渲染异常场景
    • 典型异常成因分析
  • 前端捕捉异常的方式和方法
    • js捕捉方法:try-catch(局部)
    • 前端运行环境异常捕捉方式:window.onerror等(全局)
    • 前端框架/插件/工具自带异常捕捉机制:vue、react、小程序、axios-拦截器(全局)
      • **Vue 的异常捕捉机制**
        • 1. **全局错误处理器**
        • 2. **组件级错误边界**
        • 3. **异步错误处理**
      • **React 的异常捕捉机制**
        • 1. **ErrorBoundary 组件**
        • 2. **全局错误处理(React 17+)**
        • 3. **异步错误处理**
      • **微信小程序的异常捕捉机制**
        • 1. **全局错误监听**
        • 2. **页面/组件级错误处理**
        • 3. **请求错误处理**
      • **对比总结**
    • **最佳实践建议**
    • 组件异常兜底:数据异常、动态组件异常提示、指令异常(局部)
      • 组件级异常处理方案(加了重试)
      • 动态组件异常处理
      • 自定义指令异常处理
  • 异常上报与落库的完整实现
    • 异常兜底与重试方案
    • 异常上报系统设计
    • 上报及缓存细节
  • 还有哪些异常可能会被遗漏?
    • 多场景均遇到的异常盲区
    • 框架层面的异常盲区
    • 高级异常处理方案
  • 异常处理的最佳实践与优化策略
    • 分级处理策略
    • 分层捕获:
    • 性能优化考虑
    • 异常处理的持续优化
    • 异常打印-生产环境拦截

捕获 React 异常

最近做了一个异常兜底页面的需求,基本需求的UI已经完成开发,有初步的上报和错误重试机制,想进一步在上报、捕捉上面完善,想到了“react errorBoundary”。
异常处理是前端应用稳定性保障的核心环节,一套完善的异常处理机制能够帮助开发者快速定位问题、优化用户体验。本文将以“react errorBoundary”为引子,围绕Vue/小程序组/h5渲染异常展开,系统讲解前端异常的捕捉方式、代码实践及常见遗漏场景。

异常处理的核心方法论

在前端应用中,异常处理绝非简单的错误捕获,而是需要遵循"场景分析-方案设计-实施验证-持续优化"的完整流程:

  1. 场景与原因分析:不同业务场景下的异常成因差异显著,例如社交平台的异常可能更多涉及实时通信、状态更新模块,而电商结算页的异常可能与支付接口引发的状态更新相关
  2. 分级处理策略:根据异常影响范围(页面级/模块级/函数级)和严重程度(致命/可恢复)制定不同的处理方案
  3. 闭环处理流程:捕捉→上报→落库→分析→修复形成完整闭环,避免异常处理成为"黑洞"

react的ErrorBoundary

React 在子组件抛出错误时,会自动查找最近的 ErrorBoundary 组件,并调用其 componentDidCatch 方法。多层嵌套的组件不需要层层主动触发,React 会直接将错误上抛到最近的 ErrorBoundary,并进行处理。每个层级的 componentDidCatch 都会被调用,但不需要手动触发。

ErrorBoundary 是 React 提供的一个功能,用于捕获其子组件树中的 JavaScript 错误,避免整个应用崩溃。它的原理和实现细节如下:

原理

  • 生命周期方法ErrorBoundary 组件使用 componentDidCatchgetDerivedStateFromError 两个生命周期方法来捕获错误。
  • componentDidCatch(error, info):在子组件抛出错误时被调用,可以用来记录错误信息。
  • getDerivedStateFromError(error):在发生错误时更新状态,以便渲染备用 UI。
  • 状态管理:通过维护一个状态(如 hasError),ErrorBoundary 可以控制渲染内容,显示备用 UI。

实现细节

import React from 'react';
class ErrorBoundary extends React.Component {constructor(props) {super(props);this.state = { hasError: false };}static getDerivedStateFromError(error) {// 更新状态以渲染备用 UIreturn { hasError: true };}componentDidCatch(error, errorInfo) {// 可以将错误日志上报给服务器console.error("ErrorBoundary caught an error:", error, errorInfo);}render() {if (this.state.hasError) {// 渲染备用 UIreturn <h1>Something went wrong.</h1>;}return this.props.children; }
}
export default ErrorBoundary;

使用

在应用中包裹可能出错的组件:

<ErrorBoundary><MyComponent />
</ErrorBoundary>

注意事项

  • 必须是类组件,函数组件无法直接实现 ErrorBoundary 功能。

局限性: 如react的ErrorBoundary 只能捕获子组件的 render 错误,具备无法处理的情况:

  • 事件处理函数(比如 onClick,onMouseEnter)
  • 异步代码(如requestAnimationFrame,setTimeout,promise)
  • 服务端渲染 ErrorBoundary
  • 组件本身的错误

Vue组件render异常场景及深度解析

常见渲染异常场景

Vue 的响应式系统在渲染过程中同步执行计算属性、watch 和模板表达式,任何未处理的异常都会中断整个渲染流程。这些异常会直接影响视图展示甚至导致应用崩溃:

  • 数据驱动异常

    • 未定义属性访问:{{ user.info.name }} 当user未加载完成时
    • 类型不匹配:向v-bind:style传递非对象类型数据,包含第三方库集成错误类型
    • 递归引用:组件数据中存在循环引用导致响应式系统崩溃
  • 动态渲染异常

    • 动态组件加载失败:异步组件加载过程中抛出异常
    • 模板编译错误:动态生成的模板包含语法错误
    • 指令使用不当:自定义指令钩子函数中抛出异常
    • 递归引用:组件存在循环引用导致递归组件栈溢
  • 生命周期异常

    • render()函数本身抛出错误
    • beforeUpdate/updated钩子中触发的渲染异常
    • 服务器端渲染(SSR)与客户端渲染不匹配导致的异常

典型异常成因分析

以一个实际场景为例,当我们在Vue组件中使用异步数据时:

export default {data() {return {user: null}},created() {fetchUser().then(user => {this.user = user})},template: `<div>{{ user.name }}</div>`
}

在数据未加载完成时,user.name会导致TypeError,这类异常在实际应用中非常常见,主要成因包括:

  1. 异步操作时序问题:数据尚未加载完成就被视图层访问
  2. 数据校验缺失:未对异步返回数据进行合法性校验
  3. 响应式系统边界:在某些边界情况下响应式系统未能正确追踪依赖

前端捕捉异常的方式和方法

js捕捉方法:try-catch(局部)

这个很经典了,异步、数据获取等

前端运行环境异常捕捉方式:window.onerror等(全局)

// 浏览器全局错误
window.addEventListener('error', (event) => {reportError(event.error || new Error(event.message))
})// 未处理的 Promise 异常
window.addEventListener('unhandledrejection', (event) => {reportError(event.reason)
})

window.onerror 用于捕获以下类型的异常:

  1. JavaScript 运行时错误:如语法错误、类型错误等。
  2. 资源加载错误:如图片、脚本或样式文件加载失败。
  3. 未捕获的异常:未被 try-catch 块捕获的错误。
    它无法捕获的异常包括:
  • 异步代码中的错误(需要使用 Promise.catch()unhandledrejection)。
  • setTimeoutsetInterval 中的错误。

window.addEventListener('unhandledrejection', callback):用于捕获未处理的 Promise 拒绝。

react的boundary等思路实现的组件边界,不建议添加window.onerror捕捉全局。但可以添加window.onunhandledrejection捕捉异步操作。
一是职责分离;ErrorBoundary 应专注于组件级错误,全局错误应由独立机制处理。
二是上下文不匹配,全局错误无法有效获取组件状态,难以实现针对性恢复。 三是潜在冲突:可能与其他错误监听产生冲突。

前端框架/插件/工具自带异常捕捉机制:vue、react、小程序、axios-拦截器(全局)

Vue、React 和微信小程序作为主流前端框架,都提供了内置的异常捕捉机制,用于提升应用稳定性。以下是它们的核心异常处理能力对比及最佳实践:

Vue 的异常捕捉机制

1. 全局错误处理器
// main.js
Vue.config.errorHandler = (err, vm, info) => {console.error('全局错误:', err, info);// 上报错误到监控系统
};
  • 捕获范围:组件渲染错误、生命周期钩子、事件处理函数、自定义指令等。
  • 局限性:无法捕获异步操作(如 Promise)错误。
2. 组件级错误边界

通过 errorCaptured 钩子在组件内部捕获子组件错误:

<script>
export default {errorCaptured(err, vm, info) {this.hasError = true;console.error('子组件错误:', err);// 返回 false 阻止错误向上传播return false;}
};
</script>
3. 异步错误处理
// 处理未捕获的 Promise 错误
window.addEventListener('unhandledrejection', event => {console.error('Promise 错误:', event.reason);
});

React 的异常捕捉机制

1. ErrorBoundary 组件
class ErrorBoundary extends React.Component {state = { hasError: false };static getDerivedStateFromError() {return { hasError: true };}componentDidCatch(error, errorInfo) {console.error('ErrorBoundary 捕获:', error, errorInfo);// 上报错误}render() {return this.state.hasError ? <FallbackUI /> : this.props.children;}
}
  • 捕获范围:渲染期间、生命周期方法、构造函数中的错误。
  • 局限性:无法捕获事件处理、异步代码、服务端渲染、ErrorBoundary 自身的错误。
2. 全局错误处理(React 17+)
// index.js
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<ErrorBoundary><App /></ErrorBoundary>
);
3. 异步错误处理
// 处理未捕获的 Promise 错误
window.addEventListener('unhandledrejection', event => {console.error('Promise 错误:', event.reason);
});

微信小程序的异常捕捉机制

1. 全局错误监听
// app.js
App({onLaunch() {// 监听 JS 错误wx.onError(errMsg => {console.error('JS 错误:', errMsg);});// 监听未处理的 Promise 错误wx.onUnhandledRejection(res => {console.error('Promise 错误:', res.reason);});}
});
2. 页面/组件级错误处理
// pages/index/index.js
Page({onLoad() {try {// 可能出错的代码} catch (err) {console.error('页面错误:', err);}}
});
3. 请求错误处理
wx.request({url: 'https://api.example.com',fail(err) {console.error('请求失败:', err);}
});

对比总结

特性VueReact微信小程序
错误边界errorCaptured 钩子ErrorBoundary 组件无(需手动 try-catch)
全局错误捕获Vue.config.errorHandler需手动设置 window.onerrorwx.onError
Promise 错误需监听 unhandledrejection需监听 unhandledrejectionwx.onUnhandledRejection
事件处理错误捕获不捕获(需手动处理)需手动 try-catch
异步操作错误需手动处理需手动处理需手动处理

最佳实践建议

  1. 统一错误上报:集成 Sentry 等监控工具,自动收集所有类型的错误。
  2. 分层处理错误
    • 组件级错误:使用 Vue 的 errorCaptured 或 React 的 ErrorBoundary。
    • 全局错误:通过框架提供的全局钩子(如 Vue.config.errorHandler)。
  3. 异步代码保护
    • 所有 Promise 链必须包含 .catch()
    • 使用 async/await 时,始终用 try...catch 包裹。
  4. 用户体验优化
    • 显示友好的错误提示界面,提供重试机制。
    • 记录错误上下文(如用户操作路径、设备信息)。

通过合理利用框架自带的异常处理机制,可以大幅提升应用的健壮性和用户体验。

组件异常兜底:数据异常、动态组件异常提示、指令异常(局部)

以vue来举例:

组件级异常处理方案(加了重试)

对于关键组件,我们可以实现更精细的异常处理:

<template><div class="user-profile"><!-- 异常兜底渲染 --><div v-if="hasError" class="error-container"><h3>加载用户信息失败</h3><p>点击重试按钮重新加载</p><button @click="retryLoad">重试</button></div><!-- 正常渲染内容 --><div v-else class="profile-content"><h2>{{ user.name }}</h2><p>邮箱: {{ user.email }}</p><p>注册时间: {{ user.registerTime }}</p></div></div>
</template><script>
export default {data() {return {user: null,hasError: false,retryCount: 0,maxRetries: 3}},created() {this.loadUserProfile()},methods: {loadUserProfile() {// 使用try-catch包裹可能出错的异步操作try {fetch('/api/user/profile').then(response => {if (!response.ok) {throw new Error(`HTTP错误: ${response.status}`)}return response.json()}).then(data => {this.user = datathis.hasError = false}).catch(err => {this.handleError(err)})} catch (err) {this.handleError(err)}},handleError(err) {console.error('用户信息加载异常', err)this.hasError = truethis.retryCount++// 异常上报reportError('user-profile-error', {message: err.message,retryCount: this.retryCount,component: 'UserProfile'})// 达到最大重试次数后记录失败if (this.retryCount >= this.maxRetries) {logErrorToDatabase('user-profile-load-failed', {message: err.message,userAgent: navigator.userAgent,timestamp: new Date().toISOString()})}},retryLoad() {if (this.retryCount < this.maxRetries) {this.loadUserProfile()}}}
}
</script>

动态组件异常处理

<template><div><component :is="dynamicComponent" v-if="!error" @error="handleComponentError"/><div v-else class="error-message">组件加载失败,请刷新页面重试</div></div>
</template><script>
export default {data() {return {dynamicComponent: null,error: false}},methods: {loadComponent(componentName) {// 使用异步组件加载并捕获异常this.$options.components[componentName] = () => import(`./components/${componentName}`).then(component => {this.dynamicComponent = componentNamethis.error = false}).catch(err => {this.handleError(err, `组件${componentName}加载失败`)})},handleComponentError(err) {this.error = truereportError('dynamic-component-error', {componentName: componentName,error: err.message})}}
}
</script>

自定义指令异常处理

// 自定义指令异常处理示例
Vue.directive('focus', {inserted: function(el) {try {// 使用try-catch包裹可能出错的指令逻辑el.focus()} catch (err) {console.error('focus指令异常', err)reportError('directive-error', {directive: 'focus',message: err.message})// 可以在这里添加错误恢复逻辑}}
})

异常上报与落库的完整实现

异常兜底与重试方案

// 带重试机制的请求
async function fetchWithRetry(url, options = {}, retries = 3) {try {return await fetch(url, options)} catch (err) {if (retries <= 0) throw errawait new Promise(r => setTimeout(r, 1000 * (4 - retries)))return fetchWithRetry(url, options, retries - 1)}
}// 组件级兜底 UI
<template><ErrorBoundary v-if="error" :error="error"><FallbackUI @retry="loadData" /></ErrorBoundary><MainContent v-else />
</template>

异常上报系统设计

一个完善的异常上报系统应包含以下核心模块:

// 异常通用捕捉封装方法
export function captureError(error, meta = {}) {const errorData = {timestamp: Date.now(),message: error.message,stack: error.stack,...meta}errorService.queue.push(errorData)if (document.visibilityState === 'hidden') {errorService.report()}
}// 实践1:异常元数据收集
captureError(err, {component: this.$options.name,route: this.$route.path,user: store.state.user.id,device: navigator.userAgent
})// 实践2:
const script = document.createElement('script')
script.onerror = () => {captureError(new Error(`脚本加载失败: ${script.src}`))
}

上报及缓存细节

// error-reporting.js 异常上报模块
const errorReporting = {// 上报配置config: {reportUrl: 'https://api.error-tracking-system.com/report',appId: 'your-app-id',environment: process.env.NODE_ENV || 'development'},// 基础上报方法report(errorType, errorInfo) {// 构建统一的异常上报格式const reportData = {appId: this.config.appId,environment: this.config.environment,errorType,errorInfo: {...errorInfo,// 添加环境信息timestamp: new Date().toISOString(),userAgent: navigator.userAgent,pageUrl: window.location.href,// 可以添加用户标识等信息// userId: this.getUserId(),},// 错误堆栈信息stack: errorInfo.stack || ''}// 发送上报请求this.sendToServer(reportData)},// 发送到服务器sendToServer(data) {// 生产环境使用异步请求上报if (this.config.environment === 'production') {try {const xhr = new XMLHttpRequest()xhr.open('POST', this.config.reportUrl, true)xhr.setRequestHeader('Content-Type', 'application/json')xhr.send(JSON.stringify(data))} catch (err) {console.error('异常上报发送失败', err)// 可以实现本地缓存重试机制this.cacheError(data)}} else {// 开发环境打印到控制台console.log('开发环境异常上报模拟', data)}},// 本地缓存异常(用于网络失败时重试)cacheError(data) {try {const cachedErrors = JSON.parse(localStorage.getItem('cachedErrors')) || []cachedErrors.push(data)// 限制缓存数量if (cachedErrors.length > 50) {cachedErrors.shift()}localStorage.setItem('cachedErrors', JSON.stringify(cachedErrors))// 定时重试发送缓存的异常this.scheduleRetry()} catch (err) {console.error('缓存异常失败', err)}},// 定时重试发送缓存的异常scheduleRetry() {// 每5分钟尝试发送一次缓存的异常setInterval(() => {const cachedErrors = JSON.parse(localStorage.getItem('cachedErrors')) || []if (cachedErrors.length > 0) {const error = cachedErrors.shift()this.sendToServer(error)localStorage.setItem('cachedErrors', JSON.stringify(cachedErrors))}}, 5 * 60 * 1000)}
}// 导出为插件
export default {install(Vue) {Vue.prototype.$errorReport = errorReporting}
}

还有哪些异常可能会被遗漏?

多场景均遇到的异常盲区

  • 异步代码黑洞
  • Web Worker 异常 worker.onerror = () => {}单独处理
  • 第三方脚本异常 script.onerror = () => {}
  • 内存泄漏:及时清理
  • CSS 资源异常:<link rel="stylesheet" href="missing.css" onerror="reportCssError(this)">

框架层面的异常盲区

  1. 事件处理函数异常

    • 场景:@click="doSomething"doSomething抛出异常
    • 遗漏原因:Vue的errorHandler不捕获事件处理函数中的异常
    • 解决方案:在事件处理函数中显式使用try-catch
  2. 异步操作异常

    • 场景:setTimeoutPromiserequestAnimationFrame中抛出的异常
    • 遗漏原因:这些异步操作处于Vue的响应式系统之外
    • 解决方案:使用全局unhandledrejection事件监听Promise异常,手动包裹异步操作
  3. 服务端渲染异常

    • 场景:SSR过程中发生的异常
    • 遗漏原因:客户端和服务端的异常处理环境不同
    • 解决方案:在服务端单独实现异常处理机制
  4. 第三方库异常

    • 场景:引入的第三方库抛出的异常
    • 遗漏原因:第三方库可能没有完善的异常处理
    • 解决方案:在调用第三方库的地方添加try-catch包装

高级异常处理方案

针对上述容易遗漏的场景,我们可以实现更全面的异常捕获方案:

// 增强型异常处理工具
const enhancedErrorHandling = {// 包装函数以捕获异常wrapWithErrorHandler(func, errorHandler = this.defaultErrorHandler) {return function(...args) {try {return func.apply(this, args)} catch (err) {errorHandler(err, {functionName: func.name,arguments: args,context: this})// 可以选择重新抛出异常或返回默认值// throw errreturn null}}},// 包装Promise以捕获异常wrapPromise(promise, errorHandler = this.defaultErrorHandler) {return promise.catch(err => {errorHandler(err, {promiseType: 'unknown',promiseSource: 'unknown'})throw err})},// 包装setTimeout以捕获异常wrapSetTimeout(callback, timeout, errorHandler = this.defaultErrorHandler) {return setTimeout(() => {try {callback()} catch (err) {errorHandler(err, {callbackName: callback.name,timeout: timeout})}}, timeout)},// 默认错误处理函数defaultErrorHandler(err, context) {console.error('未捕获的异常', err, context)// 上报异常reportError('uncaught-exception', {message: err.message,stack: err.stack,context: context})// 记录到数据库logErrorToDatabase('uncaught-exception', {message: err.message,stack: err.stack,context: context})}
}// 使用示例
// 包装事件处理函数
this.clickHandler = enhancedErrorHandling.wrapWithErrorHandler(function() {// 可能抛出异常的代码
})// 包装Promise
enhancedErrorHandling.wrapPromise(fetchData()).then(result => {// 处理结果
})// 包装setTimeout
enhancedErrorHandling.wrapSetTimeout(() => {// 可能抛出异常的定时任务
}, 1000)

异常处理的最佳实践与优化策略

分级处理策略

建立异常分级体系,针对不同级别的异常采取不同的处理方式:

  1. 致命异常(Fatal):导致应用崩溃或关键功能不可用

    • 处理方式:立即上报,显示友好错误页面,记录详细日志
  2. 可恢复异常(Recoverable):影响部分功能但应用仍可使用

    • 处理方式:尝试重试,显示错误提示,记录异常信息
  3. 警告异常(Warning):不影响功能但可能预示潜在问题

    • 处理方式:轻量级提示,定期汇总分析

分层捕获:

  • 全局层:window.onerror
  • 框架层:Vue errorHandler / React ErrorBoundary
  • 应用层:API 拦截器、路由守卫
  • 组件层:errorCaptured 生命周期

性能优化考虑

异常处理本身会带来一定的性能开销,需要注意以下优化点:

  1. 避免过度使用try-catch:仅在可能抛出异常的地方使用
  2. 异常信息精简:上报和存储的异常信息应去除敏感数据并适当精简
  3. 批量上报:将多个异常合并后批量上报,减少网络请求
  4. 采样上报:在高流量场景下采用采样策略,避免服务器过载

异常处理的持续优化

建立异常处理的持续优化机制:

  1. 定期分析异常数据:每周/每月分析异常趋势和分布
    • 实时错误地图
    • 错误频率趋势图
    • 用户影响范围统计
    • 异常自动归类系统
  2. 重点异常攻坚:针对高频出现的异常制定专项优化计划
  3. 异常处理测试:在测试环境中注入各种异常场景进行测试
  4. 开发流程整合:将异常处理纳入代码审查和CI/CD流程

异常打印-生产环境拦截

if (process.env.NODE_ENV === 'production') {// 禁用 console.errorconsole.error = () => {}
}

在 Vue 生产环境中阻止 console 打印的原理一般包括以下几种方法:

  1. 环境变量检查:通过检测 process.env.NODE_ENV 是否为 'production',在生产环境中有选择性地禁用 console 方法。
  2. 重写 console 方法:在生产环境中,可以重写 console.logconsole.warnconsole.error 等方法,使其不执行任何操作。
    if (process.env.NODE_ENV === 'production') {console.log = console.warn = console.error = () => {};
    }
    
  3. Webpack 插件:使用 Webpack 插件(如 terser-webpack-plugin)在构建时删除 console 调用。
  4. 全局配置:在 Vue 应用的入口文件中,可以设置全局配置来控制日志输出。
    通过这些方法,可以有效减少或完全阻止在生产环境中打印调试信息,从而提高性能和安全性。

通过上述全面的异常处理方案,我们可以构建一个健壮的前端应用,有效提升用户体验并降低维护成本。异常处理是一个持续迭代的过程,需要随着应用发展和技术演进不断优化完善。

http://www.xdnf.cn/news/1081621.html

相关文章:

  • Linux操作系统之文件(三):缓冲区
  • 每天一个前端小知识 Day 21 - 浏览器兼容性与 Polyfill 策略
  • 【每天一个知识点】动态知识库
  • JxBrowser 8.9.0 版本发布啦!
  • chrome插件合集
  • vue/微信小程序/h5 实现react的boundary
  • 智能电动汽车系列 --- 车载软件开发思想与已有OEM现状碰撞
  • vue-39(为复杂 Vue 组件编写单元测试)
  • 设计模式(十)
  • 区块链技术核心组件及应用架构的全面解析
  • Dash 安装使用教程
  • 程序计数器(PC)是什么?
  • Linux入门篇学习——Linux 帮助手册
  • 版本控制器SVN
  • 基于区块链的物联网(IoT)安全通信与数据共享的典型实例
  • 三体融合实战:Django+讯飞星火+Colossal-AI的企业级AI系统架构
  • Abase和ByteKV存储方案对比
  • [C++] C++多重继承:深入解析复杂继承关系
  • 怎么更改cursor字体大小
  • github上部署自己的静态项目
  • XILINX Kintex 7系列FPGA的全局时钟缓冲器(BUFG)和区域时钟缓冲器(BUFR/BUFH)的区别
  • hello判断
  • WPF学习笔记(23)Window、Page与Frame、ViewBox
  • 「Java案例」鸡兔同笼问题
  • [Linux]内核如何对信号进行捕捉
  • JavaWeb笔记05
  • 论文解读:《DeepGray:基于灰度图像和深度学习的恶意软件分类方法》
  • 408第三季part2 - 计算机网络 - 计算机网络基本概念
  • FastAPI 小白教程:从入门级到实战(源码教程)
  • 学习者的Python项目灵感