news 2026/7/2 22:24:44

Cypress端到端测试入门:一周搭建现代Web应用自动化测试框架

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Cypress端到端测试入门:一周搭建现代Web应用自动化测试框架

1. 项目概述:为什么是Cypress?

如果你正在为前端应用的测试而头疼,特别是那些需要模拟真实用户操作、验证整个业务流程的端到端测试,那么Cypress的出现,很可能就是你的“解药”。在过去,一提到端到端测试,很多人会立刻想到Selenium。Selenium固然强大,但它更像一个“重型武器库”,配置复杂、环境依赖多、异步操作导致的“等待”问题常常让人抓狂。而Cypress,则像一把为现代Web应用量身定制的“瑞士军刀”,它直接运行在浏览器中,与你的应用共享同一个生命周期,这让编写稳定、快速的测试变得前所未有的直观。

我最初接触Cypress,是因为一个Vue.js项目。每次发布前,团队都需要手动点击几十个页面,验证核心流程,耗时耗力且容易遗漏。引入Selenium后,脚本的维护成本又成了新问题。直到尝试了Cypress,其“所见即所得”的测试运行器、自动等待机制和清晰的错误信息,让我们在一周内就搭建起了核心业务的测试覆盖。这个“一周上手”的目标,并非夸大其词,而是基于Cypress设计哲学的可实现路径。它非常适合前端开发者、测试工程师以及任何希望提升Web应用质量与发布信心的团队。你不需要是测试专家,只要会写JavaScript,就能快速入门。

2. 核心设计思路:Cypress为何与众不同?

2.1 架构革命:从远程控制到本地共生

理解Cypress,首先要跳出传统端到端测试工具的思维定式。像Selenium这样的工具,其工作模式是“远程控制”。你的测试脚本(用Java、Python等编写)运行在一个进程中,它通过WebDriver协议向另一个独立的浏览器进程发送指令(如“点击这个按钮”),然后等待浏览器返回结果。这个通信过程是异步且跨进程的,因此不可避免地会遇到时序问题:你的脚本认为页面已经加载完成,但浏览器可能还在渲染;你试图获取一个元素,但它可能尚未出现在DOM中。为了解决这些问题,你不得不大量使用Thread.sleep或显式等待,导致测试既脆弱又缓慢。

Cypress采用了完全不同的架构。它直接运行在浏览器内部。当你启动Cypress测试时,它会启动一个专用的浏览器实例(通常是Chrome或Electron),并将你的测试代码注入到与应用程序相同的上下文中执行。这意味着Cypress的测试代码和你的前端应用代码共享同一个事件循环、内存空间和DOM。这种“共生”关系带来了几个根本性优势:

  1. 同步操作,自动等待:Cypress几乎所有的命令(如cy.get(),cy.click())都内置了智能重试和等待逻辑。当它执行cy.get(‘.submit-btn’)时,如果元素不存在,Cypress不会立即失败,而是会持续重试一小段时间,直到元素出现或超时。这彻底消除了因网络延迟或渲染速度导致的“元素未找到”的随机失败。
  2. 实时可观测:Cypress Test Runner(测试运行器)提供了一个实时交互的界面。你可以看到每个命令执行时的应用状态、网络请求、甚至控制台输出。当测试失败时,它能精确地告诉你是在哪一步、哪个命令出了问题,并附上当时的页面快照和错误详情,调试体验极佳。
  3. 访问一切:由于运行在浏览器内,Cypress可以轻松地做传统工具难以做到的事情,比如直接stub(存根)或spy(监听)window.fetchXMLHttpRequest,甚至修改浏览器函数,实现对网络请求和计时器的完全控制,这对于测试各种边界条件至关重要。

2.2 选型考量:Cypress vs. Playwright vs. Selenium

在决定采用Cypress之前,我们有必要将其与当前主流的其他选项做个快速对比,这有助于你理解它的适用边界。

  • Cypress
    • 优势:开发者体验极佳,配置简单,开箱即用,调试功能强大,对现代前端框架(React, Vue, Angular)支持好,社区活跃,插件生态丰富。
    • 局限:主要专注于Web应用测试,且同一时间只支持一个标签页,无法直接测试多标签页或浏览器扩展。其脚本语言目前仅支持JavaScript/TypeScript。对非Web协议的测试(如文件下载、桌面应用)支持较弱。
  • Playwright
    • 优势:由微软开发,支持Chromium、Firefox、WebKit三大浏览器引擎,功能非常全面。支持多页面、多上下文、模拟移动设备、拦截网络请求、生成测试代码等。支持JavaScript/TypeScript、Python、Java、.NET等多种语言。
    • 特点:更像一个现代化的、功能更强大的Selenium替代品,架构上仍属于“远程控制”,但API设计现代,能力边界更广。
  • Selenium
    • 优势:历史悠久,生态最庞大,支持几乎所有浏览器和编程语言,是行业标准。适合需要跨多种浏览器、语言环境复杂的大型企业级测试。
    • 劣势:配置复杂,异步问题多,编写稳定测试的成本高,调试困难。

如何选择?如果你的团队主要技术栈是JavaScript/TypeScript,测试对象是单页应用(SPA),追求极致的开发体验和测试稳定性,并且没有多标签页测试的强需求,那么Cypress是首选。如果你的测试场景需要覆盖多种浏览器引擎(如Safari的WebKit),或者涉及多标签页、文件下载等复杂交互,Playwright是更全能的选择。而对于需要与历史Java/.NET测试框架集成,或有极其复杂环境需求的场景,Selenium仍是可靠的备选。

3. 环境搭建与项目初始化

3.1 基础环境准备

Cypress的运行依赖于Node.js环境。这是唯一必须的前置条件。

  1. 安装Node.js:前往Node.js官网,下载并安装LTS(长期支持)版本。安装完成后,在终端运行node -vnpm -v(或yarn -v)来验证安装是否成功。建议Node.js版本在12.x以上。
  2. 创建项目:如果你还没有前端项目,可以快速创建一个。这里我们以一个简单的Vite + Vue项目为例(React或Angular同理)。
    # 使用npm创建Vue项目 npm create vue@latest my-cypress-app cd my-cypress-app npm install
    如果你已有现有项目,直接进入项目根目录即可。

3.2 安装与启动Cypress

在项目根目录下,通过npm或yarn安装Cypress。强烈建议将其作为开发依赖(devDependencies)安装。

# 使用npm npm install cypress --save-dev # 或使用yarn yarn add cypress --dev

安装完成后,你有两种方式启动Cypress:

  • 命令行初始化(推荐给新手):运行npx cypress open。第一次运行此命令时,Cypress会帮你完成一系列初始化工作:
    • 在项目根目录创建cypress/文件夹结构。
    • 生成一系列示例测试文件,涵盖基础交互、网络请求等场景,是绝佳的学习资料。
    • 自动打开Cypress Test Runner图形界面。
  • 纯命令行运行:你也可以通过npx cypress run在无头模式(没有GUI)下运行所有测试,这通常用于持续集成(CI)环境。

执行npx cypress open后,你会看到一个选择测试类型的界面。对于端到端测试,选择“E2E Testing”。Cypress会提示你选择浏览器并创建必要的配置文件,通常直接确认即可。完成后,Test Runner界面就会打开,并列出cypress/e2e目录下的所有测试文件(包括它生成的示例)。

注意:Cypress的配置文件cypress.config.js(或.ts)位于项目根目录。初始配置通常无需修改,但后续定制化(如设置基础URL、默认命令超时时间、环境变量等)都需要在这里进行。

3.3 项目目录结构解析

初始化后,你的cypress文件夹结构大致如下,理解每个文件夹的用途至关重要:

cypress/ ├── e2e/ # 【核心】存放所有端到端测试用例文件(.cy.js/.cy.ts) ├── fixtures/ # 存放静态测试数据文件(如.json) ├── support/ │ ├── commands.js # 自定义Cypress命令 │ └── e2e.js # 测试运行前的全局配置和导入 ├── downloads/ # 测试运行时下载文件的默认存储位置 └── screenshots/ # 测试失败时自动截图的存储位置 └── videos/ # 测试运行录像的存储位置(如果开启)
  • e2e/:这是你工作的主战场。每个测试文件(例如login.cy.js)对应一个测试场景或功能模块。
  • fixtures/:用于存放固定的测试数据。例如,你可以将一组标准的用户登录信息放在users.json中,然后在测试中通过cy.fixture(‘users’)加载使用,实现数据与脚本的分离。
  • support/commands.js:这是扩展Cypress能力的“神器”。你可以将常用的操作序列(如“登录”)封装成一个自定义命令cy.login(),然后在所有测试中复用,极大提升代码的可维护性和可读性。
  • support/e2e.js:每个测试文件运行前都会先执行这个文件。通常在这里导入commands.js,或者设置全局的beforeEachafterEach钩子函数(例如每次测试前都清空本地存储)。

4. 编写你的第一个端到端测试

4.1 测试文件与基本语法

让我们从一个最经典的场景开始:测试一个登录功能。在cypress/e2e目录下,新建一个文件login.cy.js

Cypress测试基于Mocha的语法结构,并结合了Chai断言库,对于有JavaScript单元测试经验的开发者来说非常亲切。

// cypress/e2e/login.cy.js describe(‘登录功能测试套件’, function() { // “beforeEach”是一个钩子函数,在每个测试用例(it)之前运行 beforeEach(() => { // 访问我们要测试的页面。这里假设我们的应用运行在本地3000端口。 // cy.visit()是Cypress最基础的命令之一,用于导航到一个URL。 cy.visit(‘http://localhost:3000/login’); }); it(‘使用正确的用户名和密码应该登录成功’, function() { // 1. 定位元素并输入内容 // cy.get()通过CSS选择器获取DOM元素。它的智能等待确保元素存在后才执行后续操作。 cy.get(‘#username’).type(‘testuser’); // 在id为username的输入框输入 cy.get(‘#password’).type(‘securepassword123’); // 2. 触发交互 cy.get(‘form’).submit(); // 提交表单 // 或者点击登录按钮:cy.get(‘button[type=“submit”]’).click(); // 3. 断言结果 - 验证登录成功后的页面状态 // 假设登录成功后跳转到首页,且首页有一个欢迎用户的元素 // cy.url() 获取当前URL, .should() 是断言链的起点 cy.url().should(‘include’, ‘/dashboard’); // 断言URL包含/dashboard cy.get(‘.welcome-message’).should(‘contain’, ‘testuser’); // 断言欢迎信息包含用户名 }); it(‘使用错误的密码应该显示错误提示’, function() { cy.get(‘#username’).type(‘testuser’); cy.get(‘#password’).type(‘wrongpassword’); cy.get(‘form’).submit(); // 断言错误提示信息出现 // 这里假设错误信息会以一个具有.error-text类的元素呈现 cy.get(‘.error-text’) .should(‘be.visible’) // 断言元素可见 .and(‘contain’, ‘密码错误’); // .and() 是.should()的别名,用于连接多个断言 }); });

代码解读与核心概念:

  • describe()it():来自Mocha,用于组织测试。describe描述一个功能模块(测试套件),it描述一个具体的测试用例。
  • cy:Cypress的全局对象,所有命令都通过它调用。
  • 命令链:Cypress命令(如cy.get())是异步的,但它们通过Promise-like的链式调用,让你可以像写同步代码一样组织逻辑。每个命令都操作上一个命令产生的结果(称为“主题”)。
  • 断言.should()是进行断言的主要方式。它非常强大,可以检查元素状态(be.visible,be.disabled)、内容(contain,have.text)、属性(have.attr,have.class)、甚至数量(have.length)。

4.2 核心命令详解与最佳实践

掌握几个核心命令,你就能应对80%的测试场景。

  1. cy.visit(url):访问一个页面。这是测试的起点。最佳实践是在beforeEach钩子中使用,确保每个测试用例都从一个干净的状态开始。
  2. cy.get(selector)使用频率最高的命令。它通过CSS选择器获取一个或多个元素。选择器的编写至关重要。
    • 最佳实践:优先使用专为测试添加的>it(‘登录时拦截API并返回模拟数据’, () => { // 拦截POST到 /api/login 的请求,并返回一个存根响应 cy.intercept(‘POST’, ‘/api/login’, { statusCode: 200, body: { success: true, token: ‘fake-jwt-token’, username: ‘mockUser’ } }).as(‘loginRequest’); // .as() 给这个拦截起个别名,方便后续引用 cy.get(‘#username’).type(‘…’); cy.get(‘#password’).type(‘…’); cy.get(‘form’).submit(); // 等待这个特定的拦截发生,并断言一些请求信息 cy.wait(‘@loginRequest’).its(‘request.body’).should(‘have.property’, ‘username’); });使用cy.intercept()能极大提升测试速度,并使测试不再依赖不稳定的后端服务,这是实现“稳定测试”的关键。
    • cy.fixture():加载fixtures/目录下的静态数据文件。
      // fixtures/users.json { “admin”: { “username”: “admin”, “password”: “admin123” } } // 在测试中 cy.fixture(‘users’).then((userData) => { cy.get(‘#username’).type(userData.admin.username); cy.get(‘#password’).type(userData.admin.password); });

4.3 页面对象模式(Page Object Model)入门

当测试用例越来越多,直接在测试文件中用cy.get定位元素会导致大量重复代码,且一旦页面结构变化,修改点会非常分散。这时,引入“页面对象模式”(POM)是明智的选择。

POM的核心思想是将页面的元素定位和基本操作封装成一个类(或对象),测试脚本只关心业务逻辑,不关心具体元素如何定位。

// cypress/support/pages/LoginPage.js class LoginPage { // 元素定位器 elements = { usernameInput: () => cy.get(‘#username’), passwordInput: () => cy.get(‘#password’), submitButton: () => cy.get(‘button[type=“submit”]’), errorMessage: () => cy.get(‘.error-text’), welcomeMessage: () => cy.get(‘.welcome-message’) }; // 页面操作/方法 visit() { cy.visit(‘/login’); } typeUsername(username) { this.elements.usernameInput().type(username); } typePassword(password) { this.elements.passwordInput().type(password); } submit() { this.elements.submitButton().click(); } // 组合操作 - 登录流程 login(username, password) { this.typeUsername(username); this.typePassword(password); this.submit(); } } export default LoginPage;

然后在测试文件中使用这个页面对象:

// cypress/e2e/loginWithPOM.cy.js import LoginPage from ‘../support/pages/LoginPage’; describe(‘使用POM测试登录’, () => { const loginPage = new LoginPage(); beforeEach(() => { loginPage.visit(); }); it(‘成功登录’, () => { loginPage.login(‘testuser’, ‘securepassword123’); // 断言可以放在Page Object里,也可以放在测试用例中。建议将验证页面状态的方法也封装在POM中。 loginPage.elements.welcomeMessage().should(‘contain’, ‘testuser’); }); });

使用POM的好处是显而易见的:可维护性(元素选择器只在一处定义)、可读性(测试用例读起来像自然语言)、可复用性(多个测试文件可以共用同一个页面对象)。

5. 高级技巧与实战配置

5.1 环境变量与动态配置

你的应用可能在不同环境(开发、测试、生产)下运行,Cypress提供了灵活的方式来管理环境相关的配置。

  1. 配置文件 (cypress.config.js):在这里设置全局配置。
    const { defineConfig } = require(‘cypress’); module.exports = defineConfig({ e2e: { baseUrl: ‘http://localhost:3000’, // 设置基础URL,之后cy.visit(‘/login’)会自动拼接 viewportWidth: 1280, viewportHeight: 720, defaultCommandTimeout: 10000, // 命令默认超时时间(毫秒) setupNodeEvents(on, config) { // 可以在这里读取环境变量,动态修改config config.baseUrl = process.env.CYPRESS_BASE_URL || config.baseUrl; return config; }, }, });
  2. Cypress环境变量:可以通过多种方式设置,优先级从高到低:命令行 >cypress.env.json> 配置文件 > 系统环境变量。
    • 创建cypress.env.json文件(记得加入.gitignore)来存储敏感或环境特定的信息:
    { “USERNAME”: “test_admin”, “PASSWORD”: “env_specific_pass” }
    • 在测试中通过Cypress.env(‘USERNAME’)Cypress.env().USERNAME来访问。
    • 在命令行运行时传入:npx cypress run --env USERNAME=ci_user,PASSWORD=ci_pass

5.2 自定义命令封装

当某个操作序列在多个测试中重复出现时(例如“登录”),就应该考虑将其封装成自定义命令。这比POM更通用,可以跨页面使用。

cypress/support/commands.js中:

// 定义一个登录命令 Cypress.Commands.add(‘login’, (username = Cypress.env(‘USERNAME’), password = Cypress.env(‘PASSWORD’)) => { cy.session([username, password], () => { // cy.session 是Cypress 12+的API,用于缓存和复用登录状态,加速测试 cy.visit(‘/login’); cy.get(‘#username’).type(username); cy.get(‘#password’).type(password); cy.get(‘form’).submit(); // 确保登录成功,例如检查是否跳转到了dashboard cy.url().should(‘include’, ‘/dashboard’); }); }); // 定义一个通用的数据清理命令 Cypress.Commands.add(‘resetDatabase’, () => { // 这里可以调用一个后端API或执行一个脚本来重置测试数据库 cy.request(‘POST’, ‘http://localhost:3000/api/test/reset-db’); });

cypress/support/e2e.js中导入命令文件:

import ‘./commands’;

现在,你可以在任何测试文件中使用cy.login()了,它甚至会自动缓存会话,避免每个测试都重复登录。

5.3 测试数据管理与工厂函数

对于复杂业务,测试数据的管理是个挑战。除了使用fixtures,还可以结合“工厂函数”来动态生成数据。

// cypress/support/factories/userFactory.js export const createUser = (overrides = {}) => { const defaultUser = { username: `testuser_${Date.now()}`, // 使用时间戳确保唯一性 email: `user_${Date.now()}@example.com`, password: ‘defaultPassword123’, role: ‘member’ }; return { …defaultUser, …overrides }; }; // 在测试中 import { createUser } from ‘../support/factories/userFactory’; it(‘注册新用户’, () => { const newUser = createUser({ role: ‘admin’ }); // 使用newUser的数据进行注册操作… // 也可以同时调用API在后台创建这个用户,用于测试需要已存在用户的场景 cy.request(‘POST’, ‘/api/users’, newUser); // 先创建用户 // 然后进行前端登录测试… });

这种方法使得测试数据既可控(可预测)又灵活(可定制),并且避免了测试间的数据冲突。

5.4 视觉回归测试与组件测试

Cypress不仅能做功能测试,还能通过插件集成做视觉回归测试(对比UI截图)和组件测试(直接测试单个UI组件)。

  • 视觉回归:可以使用cypress-image-snapshot等插件。在关键交互后(如提交表单、打开弹窗)对页面或特定元素进行截图,并与基线图对比,自动检测UI变化。
  • 组件测试:这是Cypress针对现代前端框架(React, Vue, Angular)的强力功能。它允许你像在开发环境中一样,单独挂载并测试一个组件,模拟用户交互并断言其状态和输出。这对于测试复杂的交互式组件(如表单、下拉菜单)非常高效,因为它绕过了整个应用的路由和状态管理,运行速度极快。配置通常需要额外的适配器(如@cypress/vue)。

6. 集成到开发流程与持续集成(CI)

6.1 在CI中运行Cypress

将Cypress集成到CI/CD管道(如GitHub Actions, GitLab CI, Jenkins)中,可以实现每次代码提交或合并请求时自动运行测试,保障代码质量。

以下是一个简单的GitHub Actions工作流示例(.github/workflows/cypress.yml):

name: Cypress E2E Tests on: [push, pull_request] # 在push或PR时触发 jobs: cypress-run: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: ‘18’ - name: Install dependencies run: npm ci # 使用ci命令确保依赖锁定 - name: Start development server (in background) run: npm run dev & # 启动你的前端开发服务器 - name: Wait for server to be ready run: npx wait-on http://localhost:3000 # 等待服务器启动 - name: Run Cypress tests run: npx cypress run # 在无头模式下运行所有测试 # 可以添加更多参数,如指定浏览器:--browser chrome # 或者生成报告:--reporter junit --reporter-options “mochaFile=results/test-results.xml” - name: Upload test artifacts (on failure) if: failure() # 如果测试失败,上传截图和录像以便调试 uses: actions/upload-artifact@v3 with: name: cypress-artifacts path: | cypress/screenshots cypress/videos

6.2 测试策略与选择器策略建议

  • 测试金字塔:遵循测试金字塔原则。Cypress端到端测试位于金字塔顶端,成本最高、运行最慢。底层应有大量的单元测试和集成测试。不要试图用E2E测试覆盖所有场景,应聚焦于核心用户旅程(如注册、登录、下单、支付)。
  • 选择器策略(重申):坚持使用>// 方法1:使用 .selectFile() (Cypress 9.3.0+) cy.get(‘input[type=“file”]’).selectFile(‘cypress/fixtures/example.png’); // 方法2:经典方法,将文件内容作为Blob触发change事件 cy.fixture(‘example.png’, ‘binary’).then((fileContent) => { const blob = Cypress.Blob.binaryStringToBlob(fileContent, ‘image/png’); const file = new File([blob], ‘example.png’, { type: ‘image/png’ }); const dataTransfer = new DataTransfer(); dataTransfer.items.add(file); cy.get(‘input[type=“file”]’).then($input => { $input[0].files = dataTransfer.files; // 触发change事件,通知应用文件已选择 cy.wrap($input).trigger(‘change’, { force: true }); }); });

    7.4 调试技巧

    1. 利用Test Runner:这是最强大的调试工具。你可以暂停测试执行,查看当时的DOM快照、控制台日志、网络请求和发出的Cypress命令。
    2. 使用cy.pause():在测试脚本中插入cy.pause(),测试运行到此处会暂停,你可以使用Test Runner的调试工具逐步执行后续命令。
    3. 使用cy.debug():插入cy.debug(),测试会在此处暂停,并将当前命令的主题(通常是上一个命令返回的JQuery元素)打印到开发者控制台,方便你检查。
    4. 查看命令日志:Test Runner左侧的命令日志清晰展示了每个命令的执行结果和耗时,点击任何命令可以查看其执行时的详细信息。

    一周的时间,足以让你从零开始,搭建起一个覆盖核心业务流程的Cypress端到端测试框架。关键在于动手实践,从一个最简单的登录测试开始,逐步扩展到更复杂的场景,并在这个过程中不断重构,引入页面对象、自定义命令等模式来提升代码质量。记住,好的测试应该是稳定、快速、易于理解和维护的。Cypress通过其独特的设计,大大降低了编写这类测试的门槛。当你第一次看到CI管道因为测试失败而自动阻止了一次有缺陷的代码合并时,你会觉得这一切的投入都是值得的。

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

Tabby终端:终极跨平台SSH和串口终端解决方案指南

Tabby终端:终极跨平台SSH和串口终端解决方案指南 【免费下载链接】tabby A terminal for a more modern age 项目地址: https://gitcode.com/GitHub_Trending/ta/tabby 你是否厌倦了在不同终端工具之间来回切换?作为一名开发者或运维人员&#xf…

作者头像 李华
网站建设 2026/7/2 22:21:54

Python Selenium自动化测试环境搭建:从零到一完整指南

1. 项目概述:为什么从Selenium开始?如果你刚接触自动化测试,或者想用Python写点脚本来自动点点网页、填填表单,那么“Python Selenium”这个组合几乎是你绕不开的起点。我刚开始做自动化那会儿,也在这个环节折腾过不少…

作者头像 李华
网站建设 2026/7/2 22:21:03

Navicat Mac版无限试用重置终极指南:三步轻松恢复14天试用期

Navicat Mac版无限试用重置终极指南:三步轻松恢复14天试用期 【免费下载链接】navicat_reset_mac navicat mac版无限重置试用期脚本 Navicat Mac Version Unlimited Trial Reset Script 项目地址: https://gitcode.com/gh_mirrors/na/navicat_reset_mac 你是…

作者头像 李华
网站建设 2026/7/2 22:19:32

Midscene.js:AI视觉自动化测试框架,解决跨平台UI测试难题

1. 项目概述:当AI视觉遇上跨平台测试 最近在折腾一个跨平台的移动端应用,测试环节差点把我搞崩溃。iOS、Android、Web,还有各种不同尺寸的平板和折叠屏设备,光是视觉回归测试(Visual Regression Testing)的…

作者头像 李华
网站建设 2026/7/2 22:07:45

基于arduino单片机万年历的电子万年历数字时钟电子日历闹钟温度3(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_文章底部可以扫码

基于arduino单片机万年历的电子万年历数字时钟电子日历闹钟温度3(设计源文件万字报告讲解)(支持资料、图片参考_相关定制)_文章底部可以扫码 功能说明 :通过Arduino单片机进行数据处理LCD1602液晶显示年、月、日、星期、时、分、秒、温度参数…

作者头像 李华
网站建设 2026/7/2 22:07:01

Metabase高危漏洞CVE-2021-41277复现:未授权文件读取原理与防御

1. 项目概述:一次对Metabase文件读取漏洞的深度剖析最近在整理内部安全资产时,又回顾了Metabase这个老牌开源BI工具在2021年底爆出的一个高危漏洞——CVE-2021-41277。这个漏洞的本质是一个未授权文件读取,攻击者无需任何认证,就能…

作者头像 李华