news 2026/9/4 6:00:17

MFC Tab控件开发:从CTabCtrl到可维护Tab组件的工程实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MFC Tab控件开发:从CTabCtrl到可维护Tab组件的工程实践

简介:本资源是一份面向MFC初学者与中级开发者的Tab Control定制化实现源码包,聚焦于多页界面开发中的核心控件封装与扩展实践。资源提供完整的Tabsheet类实现,通过继承CWnd并封装CTabCtrl,解决了标准MFC选项卡控件缺乏视图管理、样式定制与事件解耦等常见痛点,适用于桌面应用中需要动态切换子窗口或文档视图的场景。压缩包共含2个关键文件:Tabsheet.h声明类结构、消息映射及成员接口,Tabsheet.cpp实现选项卡增删、选中响应(TCN_SELCHANGE)、样式设置及与子窗口联动逻辑,整体仅2KB,轻量易集成。目前已有224人学习下载,开发者可直接复用该代码框架,快速构建具备数据绑定能力、支持自定义绘制与消息路由的TabSheet容器,显著降低MFC多页UI开发复杂度。

1. 标题解密:这不是乱码,而是一组MFC Tab控件开发中的典型调试痕迹

看到这个标题“TabSheet_tabsheet源文件_Tabú_TabSheet_fierce7og_MFCTabcontrol_”,第一反应不是困惑,而是会心一笑——这根本不是什么神秘代码或加密文件名,而是Windows桌面应用开发中,一个MFC程序员在调试Tab控件时留下的真实现场快照。我带过三届MFC项目组,每次新人接手老代码,几乎都会在工程目录里撞见类似命名:CMyTabSheet.cppTabSheetDlg.hMFCTabCtrlEx.cpp……而这个标题里的每一个片段,都对应着MFC Tab控件开发链条上的关键节点。

先拆解它:“TabSheet”是MFC中封装Tab页逻辑的常用类名前缀,不是官方类(MFC原生只有CTabCtrl),而是开发者自定义的CPropertySheet派生类或封装类;“tabsheet源文件”直白点明这是.cpp/.h源码文件;“Tabú”里的重音符ú绝非拼写错误——它是西班牙语或葡萄牙语键盘输入残留,说明开发者当时切换了系统输入法,更可能是深夜调试时手误敲出的字符,这种细节恰恰印证了真实开发场景;“fierce7og”看起来像随机字符串,但结合MFC资源ID命名习惯,它极大概率是Visual Studio自动生成的临时资源ID后缀(比如IDC_TABSHEET_FIERCE7OG),用于区分同名控件;最后的“MFCTabcontrol”则是整个模块的功能锚点,明确指向基于CTabCtrl的定制化实现。

为什么这个看似杂乱的标题值得深挖?因为背后藏着MFC Tab控件开发中最常被忽略的三大断层:UI结构与数据模型的割裂、Tab页生命周期管理的盲区、以及多语言/多输入法环境下的资源命名陷阱。很多团队用CTabCtrl搭出界面就以为完工,结果上线后出现Tab切换卡顿、页面白屏、资源加载失败等问题,根源往往就藏在这种“命名随意性”里。比如Tabú这个字符,在ANSI编码的旧工程中可能被解析为乱码,导致LoadString()加载失败;而fierce7og这类随机ID若未在.rc资源文件中正确定义,编译时不会报错,但运行时GetDlgItem()会返回NULL——这种问题在测试环境很难复现,却在客户现场频繁爆发。

我见过最典型的案例:某医疗设备管理软件,Tab页切换时偶发崩溃。排查两周后发现,问题出在CMyTabSheet类的析构函数里,对某个Tab页子窗口调用了DestroyWindow(),但该子窗口实际已被父对话框提前销毁。而触发这个错误的导火索,正是源文件名里那个不起眼的_fierce7og——它关联的资源ID在迁移工程时被复制粘贴遗漏,导致初始化阶段Create()失败,后续所有操作都在无效句柄上进行。所以,这个标题不是噪音,它是MFC开发者埋下的第一道诊断线索。

提示:当你在工程中看到含特殊字符(如ú、ñ、ç)或随机字符串(如fierce7og、x9k2m)的源文件名时,不要急于重命名。先检查其关联的资源ID是否在.rc文件中完整定义,再确认字符串表(.rc2)中是否有对应条目。MFC的资源加载机制对编码和ID一致性极其敏感,一个字符的偏差就可能让整个Tab页失效。

2. MFCTabControl核心机制:从CTabCtrl到可复用Tab组件的演进路径

MFC原生的CTabCtrl只是一个轻量级窗口包装器,它只负责绘制Tab标签和响应点击消息,真正的Tab页内容管理、生命周期控制、状态同步,全部需要开发者手动实现。这也是为什么几乎所有成熟MFC项目都会封装自己的CMFCTabControlCMyTabSheet——不是为了炫技,而是解决CTabCtrl无法回避的硬伤。

先看CTabCtrl的原始能力边界:它通过InsertItem()添加Tab项,用SetCurSel()切换当前页,靠TCN_SELCHANGE通知选中变化。但问题来了:当用户点击Tab时,CTabCtrl只告诉你“现在选中第3页”,却不负责创建第3页的窗口、不管理它的显示/隐藏、不处理它的资源释放。这意味着你必须在主对话框里维护一个CWnd* m_pTabPages[10]数组,手动调用Create()ShowWindow()DestroyWindow(),还要确保OnSize()时正确调整每个Tab页的位置大小。我统计过,一个中等复杂度的Tab应用,仅Tab页管理相关代码就占整个对话框类的40%以上。

于是行业自然演化出两种主流封装模式:PropertySheet式TabControl式。前者以CPropertySheet/CPropertyPage为基础,每个Tab页是一个独立的CPropertyPage派生类,由框架自动管理创建和销毁,适合向导式流程;后者则基于CTabCtrl自行封装,每个Tab页是普通CDialogCWnd,灵活性更高但需手动管理。标题中的TabSheet明显属于后者——TabSheetTabControl的变体命名,强调“页签容器”而非“属性表”。

关键突破点在于CMFCTabControl的三个核心设计:

  1. Tab页容器化:不再用裸指针数组,而是用CArray<CWnd*, CWnd*> m_arrTabPages存储页对象,并在AddTab()时自动调用Create()RemoveTab()时自动DestroyWindow()
  2. 消息路由中枢:重载PreTranslateMessage(),将Tab页内的键盘消息(如Tab键导航、Alt+Tab切换)统一拦截并转发给当前活动Tab页,避免焦点丢失;
  3. 状态持久化钩子:提供OnSaveTabState()/OnLoadTabState()虚函数,允许每个Tab页自行保存/恢复滚动位置、编辑框内容等状态,解决切换Tab时数据丢失问题。

实测对比数据很能说明问题:用原生CTabCtrl实现5个Tab页的管理,需编写约320行代码(含错误处理);而采用封装好的CMFCTabControl,核心逻辑压缩到80行以内,且稳定性提升3倍(Crash率从0.8%降至0.25%)。这个差异不是代码量的减少,而是将易错的手动内存管理,转化为可验证的RAII式资源控制。

注意:封装CMFCTabControl时,务必重写OnNotify()而非OnCommand()来处理Tab切换。因为TCN_SELCHANGE是WM_NOTIFY消息,OnCommand()无法捕获。我曾帮一家银行客户修复过一个持续半年的Bug:他们的Tab切换偶尔失灵,根源就是把TCN_SELCHANGE放在OnCommand()里处理,而某些系统主题下该消息会被CTabCtrl内部吞掉。

3. Tab页白屏与卡顿:MFC中被低估的渲染管线瓶颈

“原生微信小程序tab页面切换会白屏一瞬间”这个热搜词,表面看是小程序问题,但其技术本质与MFC Tab页白屏完全同源——都是UI线程被阻塞导致的渲染帧丢失。只不过小程序在JS线程,MFC在Win32消息循环。很多开发者误以为MFC是“本地应用就一定快”,却忽略了GDI渲染在现代高DPI屏幕下的性能陷阱。

先说白屏的直接原因:当用户点击Tab标签时,CMFCTabControl需要执行一连串同步操作——隐藏旧Tab页、显示新Tab页、调整布局、重绘控件。如果其中任一环节耗时超过16ms(即1帧时间),就会导致下一帧渲染延迟,视觉上就是“闪白”。而MFC默认的ShowWindow(SW_SHOW)MoveWindow()调用,会触发完整的窗口重绘流程,包括背景擦除、子控件重绘、字体渲染等。在含大量静态文本或图片的Tab页中,单次MoveWindow()可能消耗40ms以上。

解决方案不是简单加Invalidate(FALSE),而是重构渲染管线。我的实践方案分三层:
第一层:双缓冲防闪烁。在Tab页基类CBaseTabPage中重载OnEraseBkgnd(),直接返回TRUE跳过背景擦除,改用内存DC绘制:

BOOL CBaseTabPage::OnEraseBkgnd(CDC* pDC) { // 禁用默认擦除,避免闪烁 return TRUE; } void CBaseTabPage::OnPaint() { CPaintDC dc(this); CRect rcClient; GetClientRect(&rcClient); // 创建内存DC CDC memDC; memDC.CreateCompatibleDC(&dc); CBitmap bmp; bmp.CreateCompatibleBitmap(&dc, rcClient.Width(), rcClient.Height()); CBitmap* pOldBmp = memDC.SelectObject(&bmp); // 先用纯色填充背景 memDC.FillSolidRect(&rcClient, GetSysColor(COLOR_WINDOW)); // 再绘制所有子控件 for (int i = 0; i < m_arrControls.GetSize(); i++) { m_arrControls[i]->DrawToDC(&memDC); // 自定义绘制逻辑 } // 一次性BitBlt到屏幕 dc.BitBlt(0, 0, rcClient.Width(), rcClient.Height(), &memDC, 0, 0, SRCCOPY); memDC.SelectObject(pOldBmp); }

第二层:异步Tab切换。将Tab页显示逻辑从TCN_SELCHANGE消息中剥离,改为PostMessage发送自定义消息:

// 在TCN_SELCHANGE处理中 PostMessage(WM_TAB_SWITCH_ASYNC, (WPARAM)newIndex, 0); // 在WM_TAB_SWITCH_ASYNC中执行耗时操作 LRESULT CMyTabSheet::OnTabSwitchAsync(WPARAM wParam, LPARAM lParam) { int newIndex = (int)wParam; // 隐藏旧页(快速) m_pCurrentPage->ShowWindow(SW_HIDE); // 显示新页(异步) AfxBeginThread(SwitchTabThreadProc, new SwitchTabParam(this, newIndex)); return 0; }

第三层:硬件加速兜底。对含视频播放器的Tab页(如热搜词提到的uniapp场景),强制启用DirectComposition:

// 在Tab页OnInitDialog()中 if (IsWindows8OrGreater()) { HWND hWnd = m_videoCtrl.GetSafeHwnd(); SetWindowLongPtr(hWnd, GWL_EXSTYLE, GetWindowLongPtr(hWnd, GWL_EXSTYLE) | WS_EX_COMPOSITED); }

这套组合拳的效果是:Tab切换平均耗时从62ms降至11ms,白屏现象彻底消失。更重要的是,它让Tab页具备了“流式加载”能力——新Tab页显示时,内容可以分块渲染(如先画框架,再异步加载数据),用户体验从“等待”变为“渐进呈现”。

经验提醒:不要在OnSize()中直接调用MoveWindow()调整所有Tab页位置。MFC的MoveWindow()会触发重绘,而OnSize()本身就在重绘流程中。正确做法是先SetWindowPos()设置位置,再统一InvalidateRect()触发一次重绘。

4. 输入法与资源ID陷阱:特殊字符如何让MFC Tab控件静默崩溃

标题里的Tabú和热搜词“word中tab键距离不一样”看似无关,实则揭示了同一个底层问题:Windows API对Unicode和ANSI编码的混合处理,会在MFC资源系统中制造隐蔽的雪崩效应Tabú中的重音符ú在UTF-8中是C3 BA两个字节,但在ANSI代码页(如CP1252)中是单字节FA。当Visual Studio用UTF-8保存.rc文件,而MFC资源编译器(RC.exe)用ANSI解析时,Tabú就会变成Tab,导致资源ID查找失败。

这个Bug的典型症状是:程序能编译通过,运行时Tab页正常显示,但点击Tab标签毫无反应。调试发现OnNotify()根本没收到TCN_SELCHANGE消息。进一步追踪,发现CTabCtrl::GetItemCount()返回0——控件里根本没有Tab项!根源在于InsertItem()调用时传入的TCITEM结构体中pszText字段指向了一个被截断的字符串。因为.rc文件中定义的字符串表(STRINGTABLE)因编码不匹配而加载失败,LoadString()返回空字符串,CTabCtrl拒绝插入空Tab项。

解决方案必须从工程配置源头堵死:

  1. 统一工程编码:在VS中右键项目→属性→常规→字符集,强制设为“使用Unicode字符集”;
  2. .rc文件声明编码:在.rc文件顶部添加#pragma code_page(65001)(UTF-8);
  3. 字符串表强制UTF-8:在.rc2文件中,所有字符串用L"Tabú"宽字符格式,而非"Tabú"
  4. 资源ID命名规范:禁用任何非ASCII字符命名资源ID,IDC_TAB_PAGE_1IDC_TAB_PAGE_Ú安全一万倍。

更隐蔽的陷阱来自alt+tab热键冲突。MFC默认将ALT+TAB作为系统级快捷键,但如果你在Tab页内自定义了OnKeyDown()处理VK_TAB,就可能干扰系统热键。实测发现,当Tab页中有CEdit控件且获得焦点时,ALT+TAB会先触发CEdit::OnKeyDown(),若该函数未调用CWnd::OnKeyDown(),系统热键就被吞掉。修复只需一行:

void CMyEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { if (nChar == VK_TAB && (GetKeyState(VK_MENU) & 0x8000)) { // ALT+TAB交给系统处理 CEdit::OnKeyDown(nChar, nRepCnt, nFlags); return; } // 其他逻辑... }

这些细节看似琐碎,却是MFC项目稳定性的分水岭。我经手的23个MFC项目中,有17个的首版崩溃报告都指向编码或资源ID问题。它们不会在单元测试中暴露,却在客户现场高频触发——因为客户电脑的区域设置、输入法、甚至Office版本都可能改变系统默认编码行为。

关键检查清单:

  • 编译后检查.map文件,确认所有资源ID(如IDC_TABSHEET_FIERCE7OG)都被正确链接;
  • 运行时用Spy++查看Tab控件的WM_GETTEXT响应,验证Tab标签文本是否正确;
  • 在不同区域设置的虚拟机中测试Tab切换,观察是否出现TCN_SELCHANGE丢失。

5. Tab页状态管理:从“页面切换”到“上下文感知”的范式升级

热搜词“uniapp捕捉当前正在播放视频的页面切换到tab页暂停视频”点出了一个跨平台共性需求:Tab页不能只是视觉容器,必须成为有状态的上下文单元。MFC中,这要求我们超越ShowWindow()/HideWindow()的简单开关,构建一套完整的Tab页生命周期协议。

标准协议包含五个状态钩子:

  • OnTabActivate():Tab页获得焦点时调用,用于恢复播放、刷新数据;
  • OnTabDeactivate():Tab页失去焦点时调用,用于暂停视频、保存草稿;
  • OnTabVisible():Tab页首次显示时调用,用于初始化资源;
  • OnTabHidden():Tab页被隐藏时调用,用于释放显存、关闭网络连接;
  • OnTabDestroy():Tab页销毁前调用,用于清理临时文件、注销事件监听。

实现的关键是消息路由机制。CMFCTabControl需在OnNotify()中识别TCN_SELCHANGE,然后遍历所有Tab页,对旧页调用OnTabDeactivate(),对新页调用OnTabActivate()。但这里有个经典陷阱:如果Tab页的OnTabDeactivate()中执行耗时操作(如数据库提交),会导致Tab切换卡顿。因此必须支持异步状态切换:

class CTabPage : public CWnd { public: virtual void OnTabDeactivate() { // 启动异步保存任务 AfxBeginThread(SaveDraftThread, this); } static UINT SaveDraftThread(LPVOID pParam) { CTabPage* pPage = (CTabPage*)pParam; pPage->DoSaveDraft(); // 耗时操作 // 保存完成后,PostMessage通知Tab控件 pPage->PostMessage(WM_TAB_SAVE_COMPLETE, 0, 0); return 0; } };

更进一步,我们可以引入状态缓存。对于含视频播放器的Tab页,OnTabDeactivate()不直接暂停,而是记录当前播放时间戳;OnTabActivate()时根据时间戳决定是继续播放还是重新加载。这样即使用户快速切换Tab,视频也能无缝衔接。实测数据显示,这种“状态快照”机制使视频Tab页的切换感知延迟降低73%。

另一个重要维度是Tab页间的通信。原生MFC没有类似uniapp的$emit/$on机制,但我们可以通过CMFCTabControl的中央事件总线实现:

// 在Tab控件中定义事件总线 class CMFCTabControl { public: void EmitEvent(LPCTSTR lpszEvent, WPARAM wParam = 0, LPARAM lParam = 0) { for (int i = 0; i < m_arrTabPages.GetSize(); i++) { m_arrTabPages[i]->OnTabEvent(lpszEvent, wParam, lParam); } } }; // 在Tab页中监听 void CVideoTabPage::OnTabEvent(LPCTSTR lpszEvent, WPARAM wParam, LPARAM lParam) { if (_tcscmp(lpszEvent, _T("PLAYBACK_RATE_CHANGED")) == 0) { m_pVideoCtrl->SetPlaybackRate((double)wParam); } }

这套机制让Tab页从被动容器变为主动参与者。当用户在“设置Tab页”中修改播放速度时,EmitEvent(_T("PLAYBACK_RATE_CHANGED"), newRate)会立即通知所有视频Tab页同步更新,无需重启应用。

实战技巧:为避免内存泄漏,OnTabDestroy()中必须取消所有Pending的异步任务。我在CBaseTabPage基类中添加了m_hCancelEvent事件句柄,OnTabDestroy()调用SetEvent(m_hCancelEvent),所有工作线程在循环中WaitForSingleObject(m_hCancelEvent, 0)检测退出信号。

6. 工程化落地:从零搭建可维护的MFCTabControl模块

现在把所有碎片整合成可交付的工程模块。我提供的不是Demo代码,而是经过12个商业项目验证的生产级模板,包含目录结构、关键类设计、以及避坑指南。

目录结构(符合MFC工程惯例):

/MFCTabControl/ ├── /include/ // 头文件 │ ├── MFCTabControl.h // 主控件头文件 │ ├── TabPageBase.h // Tab页基类 │ └── TabEventBus.h // 事件总线 ├── /src/ // 源文件 │ ├── MFCTabControl.cpp │ ├── TabPageBase.cpp │ └── TabEventBus.cpp └── /res/ // 资源文件 ├── TabControl.rc // Tab控件专属资源 └── TabControl.rc2 // 字符串表

核心类设计要点

  • CMFCTabControl继承自CWnd而非CTabCtrl,因为它需要管理子窗口(Tab页),而CTabCtrl是纯标签控件;
  • 所有Tab页必须继承CTabPageBase,该基类强制实现OnTabActivate()等五个钩子函数;
  • 事件总线CTabEventBus采用单例模式,但提供RegisterListener()/UnregisterListener()避免内存泄漏;
  • 资源ID全部以IDC_TABCTRL_为前缀,杜绝fierce7og类随机命名。

最关键的初始化步骤(新手最容易错):

  1. 在主对话框.h中声明成员变量:CMFCTabControl m_tabCtrl;
  2. OnInitDialog()中创建控件:
// 必须指定WS_CHILD | WS_VISIBLE | WS_TABSTOP m_tabCtrl.Create(WS_CHILD | WS_VISIBLE | WS_TABSTOP, CRect(10, 10, 500, 400), this, IDC_TABCTRL_MAIN); // 添加Tab页(顺序即显示顺序) m_tabCtrl.AddTab(new CVideoTabPage(), _T("视频")); m_tabCtrl.AddTab(new CSettingsTabPage(), _T("设置"));
  1. 重载主对话框的PreTranslateMessage()
BOOL CMainDlg::PreTranslateMessage(MSG* pMsg) { // 将Tab页内消息路由给Tab控件 if (m_tabCtrl.GetSafeHwnd() && ::IsChild(m_tabCtrl.GetSafeHwnd(), pMsg->hwnd)) { return m_tabCtrl.PreTranslateMessage(pMsg); } return CDialogEx::PreTranslateMessage(pMsg); }

这个PreTranslateMessage()重载是Tab页键盘导航(如Tab键切换焦点)的生命线。漏掉它,Tab页内的控件就无法接收键盘消息,用户必须用鼠标点选——这在工业控制软件中是致命缺陷。

最后分享一个血泪教训:某电力监控系统上线后,客户投诉“Tab页偶尔打不开”。排查发现,问题出在AddTab()时传入了栈对象指针:m_tabCtrl.AddTab(&m_videoPage, _T("视频"));。当函数返回后,m_videoPage被析构,但Tab控件仍持有其野指针。修复方案是所有Tab页必须动态分配m_tabCtrl.AddTab(new CVideoTabPage(), _T("视频"));,并在CMFCTabControl析构时自动delete

最终建议:在CMFCTabControl构造函数中添加断言检查:

CMFCTabControl::CMFCTabControl() { ASSERT(AfxGetModuleState()->m_bDLL == FALSE); // 确保非DLL环境 }

因为MFC Tab控件在DLL中使用时,资源加载路径会异常,这是另一个深坑。

这个模块已在多个项目中稳定运行超5年,累计处理Tab页切换超2亿次。它证明了一件事:MFC不是过时技术,而是被低估的工程利器——只要用对方法,它依然能构建出响应迅速、状态可靠、易于维护的现代桌面应用。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/4 6:00:07

Arduino控制SG90 360度连续旋转舵机:脉宽、校准与开环控制

拿到一个丝印上写着“SG90”的舵机&#xff0c;如果它是 360 度连续旋转版本&#xff0c;请立刻忘掉“标准舵机是按角度转动”的习惯。你会发现servo.write(90)并不能让它停在中间&#xff0c;servo.write(0)也不会让它转 180 度后再停下来。它可能一直转&#xff0c;也可能在某…

作者头像 李华
网站建设 2026/9/4 6:00:06

小迪安全学习笔记-Day3 拓展模式以及测试会遇到的问题

Day3 拓展模式以及测试会遇到的问题WAF&#xff1a;Web应用防火墙&#xff0c;会对出入站流量进行过滤&#xff0c;安全测试手法遭到拦截。绕防火墙一般是绕很拉的防火墙&#xff0c;或者本身技术很高超能绕过。正常情况很难绕过的&#xff0c;从其他方面入手。CDN&#xff1a;…

作者头像 李华
网站建设 2026/9/4 5:59:58

MiniMax H3提示词工程:用标签工作台结构化生成标准提示词

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/4 5:58:26

YOLOv8在煤矿传送带异物检测中的工业级应用实践

简介&#xff1a;本资源是面向煤矿智能化安监场景的YOLOv8轻量级异物检测模型&#xff0c;专为传送带实时监控系统设计&#xff0c;解决矸石与锚杆两类关键异物漏检、误检问题&#xff0c;适用于算法工程师、矿山自动化开发者及计算机视觉初学者开展工业缺陷检测实践。压缩包共…

作者头像 李华
网站建设 2026/9/4 5:58:19

晶振负载电容:从皮尔斯振荡器原理到硬件设计实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/4 5:58:19

Graphql学习笔记

前言&#xff1a; 之前大致的了解了Graphql,websocket,rpc,restfulapi.由于现在比赛需要所以单独把这些部分拿出来再学一下,重点在前三位,rest的我个人认为偏向于接口fuzz类所以就不细说它。 本次使用的靶场是用ai大人搓的一个,还有待优化,希望各位可以提出建议.github地址我…

作者头像 李华