news 2026/9/12 22:08:22

Cloudflare Turnstile 无感人机验证实战指南:从隐式渲染到 Workers 服务端校验

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Cloudflare Turnstile 无感人机验证实战指南:从隐式渲染到 Workers 服务端校验

Cloudflare Turnstile 无感人机验证实战指南:从隐式渲染到 Workers 服务端校验

【免费下载链接】skillsSkills Catalog for Codex项目地址: https://gitcode.com/GitHub_Trending/skills4/skills

本文是 cloudflare-deploy Skill 中 Turnstile 参考模块(turnstile/README.md)的完整展开:它面向在 Cloudflare 平台(Workers / Pages)上构建应用时需防护机器人流量的场景,系统讲解 Turnstile 的三种 Widget 类型、隐式/显式渲染两种接入方式、服务端 siteverify 校验、完整配置项与 JavaScript API。读完本文,你将能够在自己的站点/表单中落地一套"无需用户点击、后台自动完成"的人机验证方案,并具备排查令牌过期、CSP 拦截、密钥泄漏等常见问题的能力。

一、Turnstile 是什么:无感 CAPTCHA 的运作方式

Turnstile 是 Cloudflare 提供的智能验证码替代方案,核心设计目标是:在后台运行验证挑战,全程不需要用户交互。它不再要求用户识别扭曲文字、勾选图片或做数学题,而是通过浏览器行为信号、设备指纹以及机器学习模型自动判定访客是否为真人。

从该参考模块的定位看,Turnstile 属于 cloudflare-deploy 安全产品线中与 WAF、DDoS、Bot Management、API Shield 并列的"CAPTCHA 替代"选项(见 SKILL.md 安全决策树)。与 Bot Management 这类面向网络层的机器人管理不同,Turnstile 以"验证码"的形式嵌入到具体的表单、登录页或 API 调用流程中,二者可组合使用。

Widget 三种类型对比

Turnstile 提供三种 Widget 模式,按用户可见性与交互方式区分,适用场景也不同:

类型交互方式适用场景
Managed(默认)仅在需要时显示复选框表单、登录页——在用户体验与安全性之间取得平衡
Non-Interactive不可见,自动运行低风险操作,追求零摩擦体验
Invisible隐藏,由程序触发预放行(Pre-clearance)、API 调用、无头环境

其中 Managed 模式最接近传统 reCAPTCHA v2 的"复选框"体验,但默认情况下大多数真人用户甚至看不到任何验证界面;Non-Interactive 模式对用户完全透明;Invisible 模式则适合在页面加载阶段提前完成验证、把生成的令牌缓存下来供后续表单或 API 请求使用(对应下文"预放行"模式)。

二、快速上手:三步完成最小可运行接入

1. 隐式渲染(纯 HTML 方式)

隐式渲染只需两步:加载官方脚本,然后在表单中放置一个带cf-turnstile类名的容器元素,脚本加载完成后会自动完成渲染:

<!-- 1. 加载脚本 --> <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script> <!-- 2. 在表单中放置 widget --> <form action="/submit" method="POST"> <div class="cf-turnstile"><div id="turnstile-container"></div> <script src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit"></script> <script> window.turnstile.render('#turnstile-container', { sitekey: 'YOUR_SITE_KEY', callback: (token) => console.log('Token:', token) }); </script>

render()的容器参数既可以是 CSS 选择器字符串,也可以是 DOM 元素;返回值是 widgetId 字符串,后续的reset()remove()getResponse()等 API 都依赖它。

3. 服务端校验(必需步骤)

任何客户端校验都不足以构成安全边界,令牌必须由服务端调用 siteverify 接口确认。以下是 Cloudflare Workers 中的标准实现:

// Cloudflare Workers export default { async fetch(request) { const formData = await request.formData(); const token = formData.get('cf-turnstile-response'); const result = await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ secret: env.TURNSTILE_SECRET, // 密钥,只能存在于服务端 response: token, remoteip: request.headers.get('CF-Connecting-IP') // 可选但推荐 }) }); const validation = await result.json(); if (!validation.success) { return new Response('Invalid CAPTCHA', { status: 400 }); } // Process form... } }

env.TURNSTILE_SECRET是配置在 Worker 上的 Secret 绑定,绝不能暴露到客户端代码中。remoteip传用户真实 IP(Workers 中取CF-Connecting-IP请求头)有助于 Cloudflare 侧的风控判断。

三、脚本加载的四种方式与兼容模式

Turnstile 官方脚本https://challenges.cloudflare.com/turnstile/v0/api.js支持通过 URL 查询参数切换行为(详见 configuration.md):

加载方式脚本 URL行为
基础(隐式渲染)api.js(可加async defer页面加载时自动渲染所有class="cf-turnstile"的容器
显式渲染api.js?render=explicit关闭自动渲染,完全由window.turnstile.render()控制
加载回调api.js?onload=myCallback脚本就绪后调用指定全局函数,在回调内执行渲染
兼容模式api.js?compat=recaptcha暴露grecaptchaAPI,可作为 Google reCAPTCHA 的平替接入

加载回调的典型用法:

<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?onload=myCallback"></script> <script> function myCallback() { // API 已就绪 window.turnstile.render('#container', { sitekey: 'YOUR_SITE_KEY' }); } </script>

也可以使用约定的window.onloadTurnstileCallback全局函数名(见 api.md):

<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?onload=onloadTurnstileCallback"></script> <script> window.onloadTurnstileCallback = () => { window.turnstile.render('#container', { sitekey: 'YOUR_SITE_KEY' }); }; </script>

四、Widget 配置项全解

完整配置对象

显式渲染时通过render()的第二个参数传入配置对象;隐式渲染时则通过 HTML 的data-*属性(见下文映射表)。完整选项如下:

{ // 必填 sitekey: 'YOUR_SITE_KEY', // 从 Dashboard 获取的站点密钥 // 回调 callback: (token) => {}, // 校验成功,令牌已就绪 'error-callback': (code) => {}, // 发生错误,code 为错误码 'expired-callback': () => {}, // 令牌过期(超过 5 分钟) 'timeout-callback': () => {}, // 验证挑战超时 'before-interactive-callback': () => {}, // 显示复选框之前触发 'after-interactive-callback': () => {}, // 用户交互之后触发 'unsupported-callback': () => {}, // 浏览器不支持 Turnstile 时触发 // 外观 theme: 'auto', // 'light' | 'dark' | 'auto' size: 'normal', // 'normal' | 'compact' | 'flexible' tabindex: 0, // Tab 键顺序(无障碍支持) language: 'auto', // ISO 639-1 语言码或 'auto' // 行为 execution: 'render', // 'render'(默认,渲染即开始挑战)| 'execute'(等待手动触发) appearance: 'always', // 'always' | 'execute' | 'interaction-only' retry: 'auto', // 'auto' | 'never' 'retry-interval': 8000, // 重试间隔(毫秒),默认 8000 'refresh-expired': 'auto', // 'auto' | 'manual' | 'never' // 表单集成 'response-field': true, // 是否注入隐藏输入域(默认 true) 'response-field-name': 'cf-turnstile-response', // 隐藏输入域的名称 // 分析与数据 action: 'login', // 行为名称(用于分析统计) cData: 'user-session-123', // 自定义数据(siteverify 响应中原样返回) }

关键行为选项说明

execution(挑战触发时机)

  • 'render'(默认):渲染后立即开始挑战;
  • 'execute':等待应用调用turnstile.execute()才启动挑战,适合"提交按钮点击后才验证"的场景。

appearance(可见性)

  • 'always'(默认):Widget 始终可见;
  • 'execute':隐藏,直到调用execute()后才显示;
  • 'interaction-only':隐藏,直到需要用户交互时才出现。

refresh-expired(令牌过期后的处理策略)

  • 'auto'(默认):自动刷新过期令牌;
  • 'manual':应用必须在expired-callback中手动调用reset()
  • 'never':不刷新,直接触发expired-callback

retry(挑战失败重试)

  • 'auto'(默认):自动重试失败的挑战;
  • 'never':不重试,直接触发error-callback

HTML data 属性映射

隐式渲染下,所有配置项都可以在<div class="cf-turnstile">上用data-*属性表达:

JavaScript 属性HTML data 属性示例
sitekeydata-sitekeydata-sitekey="YOUR_KEY"
actiondata-actiondata-action="login"
cDatadata-cdatadata-cdata="session-123"
callbackdata-callbackdata-callback="onSuccess"
error-callbackdata-error-callbackdata-error-callback="onError"
expired-callbackdata-expired-callbackdata-expired-callback="onExpired"
timeout-callbackdata-timeout-callbackdata-timeout-callback="onTimeout"
themedata-themedata-theme="dark"
sizedata-sizedata-size="compact"
tabindexdata-tabindexdata-tabindex="0"
response-fielddata-response-fielddata-response-field="false"
response-field-namedata-response-field-namedata-response-field-name="token"
retrydata-retrydata-retry="never"
retry-intervaldata-retry-intervaldata-retry-interval="5000"
languagedata-languagedata-language="en"
executiondata-executiondata-execution="execute"
appearancedata-appearancedata-appearance="interaction-only"
refresh-expireddata-refresh-expireddata-refresh-expired="manual"

综合示例:

<div class="cf-turnstile" ><meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' https://challenges.cloudflare.com; frame-src https://challenges.cloudflare.com;">

六、框架集成方案

React

npm install @marsidev/react-turnstile
import Turnstile from '@marsidev/react-turnstile'; <Turnstile siteKey="YOUR_SITE_KEY" onSuccess={(token) => console.log(token)} />

Vue

npm install vue-turnstile
<template> <VueTurnstile site-key="YOUR_SITE_KEY" @success="onSuccess" /> </template> <script setup> import VueTurnstile from 'vue-turnstile'; </script>

Svelte

npm install svelte-turnstile
<script> import Turnstile from 'svelte-turnstile'; </script> <Turnstile siteKey="YOUR_SITE_KEY" on:turnstile-callback={handleToken} />

Next.js(App Router)

由于window.turnstile只在客户端存在,组件必须标记为'use client',并在useEffect中渲染、在清理函数中移除,避免 SSR 水合问题:

// app/components/TurnstileWidget.tsx 'use client'; import { useEffect, useRef } from 'react'; export default function TurnstileWidget({ sitekey, onSuccess }) { const ref = useRef<HTMLDivElement>(null); useEffect(() => { if (ref.current && window.turnstile) { const widgetId = window.turnstile.render(ref.current, { sitekey, callback: onSuccess }); return () => window.turnstile.remove(widgetId); } }, [sitekey, onSuccess]); return <div ref={ref} />; }

Cloudflare Pages 插件

若站点托管在 Cloudflare Pages,可用官方插件在 Functions 层统一拦截校验,无需手写 siteverify 逻辑:

npm install @cloudflare/pages-plugin-turnstile
// functions/_middleware.ts import turnstilePlugin from '@cloudflare/pages-plugin-turnstile'; export const onRequest = turnstilePlugin({ secret: 'YOUR_SECRET_KEY', onError: () => new Response('CAPTCHA failed', { status: 403 }) });

七、客户端 JavaScript API 参考

脚本加载完成后,API 暴露在window.turnstile上(完整接口见 api.md):

方法签名说明
renderrender(container, options): string渲染 Widget,返回 widgetId
resetreset(widgetId): void重置 Widget(清除令牌与挑战状态),表单校验失败时常用
removeremove(widgetId): void将 Widget 从 DOM 中彻底移除
getResponsegetResponse(widgetId): string \| undefined获取当前令牌,未就绪时返回 undefined
isExpiredisExpired(widgetId): boolean判断令牌是否已过期(超过 5 分钟)
executeexecute(container?, options?): void手动触发挑战(配合execution: 'execute'

典型用法:

// 渲染 const widgetId = window.turnstile.render('#my-container', { sitekey: 'YOUR_SITE_KEY', callback: (token) => console.log('Success:', token), 'error-callback': (code) => console.error('Error:', code) }); // 表单校验失败时重置 if (!validateForm()) { window.turnstile.reset(widgetId); } // 导航时清理 window.turnstile.remove(widgetId); // 提交前读取令牌 const token = window.turnstile.getResponse(widgetId); if (token) { submitForm(token); } // 过期检查 if (window.turnstile.isExpired(widgetId)) { window.turnstile.reset(widgetId); }

回调函数签名(TypeScript):

type TurnstileCallback = (token: string) => void; type ErrorCallback = (errorCode: string) => void; type TimeoutCallback = () => void; type ExpiredCallback = () => void; type BeforeInteractiveCallback = () => void; type AfterInteractiveCallback = () => void; type UnsupportedCallback = () => void;

window.turnstile的完整 TypeScript 声明还包含onloadTurnstileCallback的全局类型扩展,方便在 TS 项目中直接使用。

八、Siteverify 服务端校验 API

端点:https://challenges.cloudflare.com/turnstile/v0/siteverify方法:POST,Content-Type支持application/jsonapplication/x-www-form-urlencoded

请求结构

interface SiteverifyRequest { secret: string; // 你的密钥,绝不能暴露在客户端 response: string; // 来自 cf-turnstile-response 的令牌 remoteip?: string; // 用户 IP(可选但推荐) idempotency_key?: string; // 幂等校验用的唯一键 }

响应结构

interface SiteverifyResponse { success: boolean; // 校验结果 challenge_ts?: string; // 挑战完成时的 ISO 时间戳 hostname?: string; // 完成 Widget 挑战的主机名 'error-codes'?: string[]; // success 为 false 时的错误码 action?: string; // Widget 配置中的 action 名 cdata?: string; // Widget 配置中的自定义数据 }

成功响应示例:

{ "success": true, "challenge_ts": "2024-01-15T10:30:00Z", "hostname": "example.com", "action": "login", "cdata": "user123" }

失败响应示例:

{ "success": false, "error-codes": ["timeout-or-duplicate"] }

利用响应中的actioncdata,服务端还可以进一步核对本次验证对应的业务上下文(例如期望的 action 是否为login),实现更细粒度的校验。

错误码速查

错误码原因解决办法
missing-input-secret未提供密钥在请求中带上secret
invalid-input-secret密钥错误到 Dashboard 核对密钥
missing-input-response未提供令牌请求中带上response令牌
invalid-input-response令牌无效或格式错误确认令牌来自 Widget
timeout-or-duplicate令牌过期(>5 分钟)或已被复用生成新令牌,且令牌只能校验一次
internal-errorCloudflare 服务端错误指数退避重试
bad-request请求格式错误检查 JSON / 表单编码

九、测试密钥:开发期必备

Cloudflare 为开发与测试提供了固定的测试密钥(见 README.md 的 Testing Keys 一节):

类型密钥行为
Site Key(始终通过)1x00000000000000000000AAWidget 成功,令牌可正常校验
Site Key(始终拦截)2x00000000000000000000ABWidget 可见地失败
Site Key(强制挑战)3x00000000000000000000FF始终显示交互式挑战
Secret Key(测试)1x0000000000000000000000000000000AA可校验测试令牌

注意:测试密钥可在localhost及任意域名上工作,切勿用于生产环境

推荐按环境切换密钥,避免测试密钥泄漏到线上:

const SITE_KEY = process.env.NODE_ENV === 'production' ? 'YOUR_PRODUCTION_SITE_KEY' : '1x00000000000000000000AA'; // 始终通过 const SECRET_KEY = process.env.NODE_ENV === 'production' ? process.env.TURNSTILE_SECRET : '1x0000000000000000000000000000000AA';

十、核心约束:必须遵守的三条红线

来自 README.md 的 Key Constraints,是上线前必须逐条核对的设计前提:

  • 令牌有效期 5 分钟:令牌生成后 5 分钟即失效,页面停留过久会导致提交时校验失败;
  • 令牌单次使用:每个令牌只能成功校验一次,重复校验会返回timeout-or-duplicate
  • 必须服务端校验:仅靠客户端检查很容易被绕过,服务端 siteverify 是不可省略的安全边界。

同时可参考 gotchas.md 中的限制速查:

限制项影响
令牌有效期5 分钟过期后必须重新生成
令牌使用次数单次同一令牌不能重复校验
Widget 尺寸300x65px(normal)、130x120px(compact)布局时需要预留空间

十一、常见集成模式

基本表单(隐式渲染)

<!DOCTYPE html> <html> <head> <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script> </head> <body> <form action="/submit" method="POST"> <input type="email" name="email" required> <div class="cf-turnstile"><script src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit"></script> <script> let widgetId = window.turnstile.render('#container', { sitekey: 'YOUR_SITE_KEY', callback: (token) => console.log('Token:', token) }); form.addEventListener('submit', async (e) => { e.preventDefault(); const token = window.turnstile.getResponse(widgetId); if (!token) return; const response = await fetch('/submit', { method: 'POST', body: JSON.stringify({ 'cf-turnstile-response': token }) }); if (!response.ok) window.turnstile.reset(widgetId); }); </script>

Workers 服务端校验(完整版)

interface Env { TURNSTILE_SECRET: string; } export default { async fetch(request: Request, env: Env): Promise<Response> { if (request.method !== 'POST') { return new Response('Method not allowed', { status: 405 }); } const formData = await request.formData(); const token = formData.get('cf-turnstile-response'); if (!token) { return new Response('Missing token', { status: 400 }); } // 校验令牌 const ip = request.headers.get('CF-Connecting-IP'); const result = await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ secret: env.TURNSTILE_SECRET, response: token, remoteip: ip }) }); const validation = await result.json(); if (!validation.success) { return new Response('CAPTCHA validation failed', { status: 403 }); } // 处理表单... return new Response('Success'); } };

Pages Functions 版本

与 Workers 模式相同,使用ctx.envctx.request

// functions/submit.ts export const onRequestPost: PagesFunction<{ TURNSTILE_SECRET: string }> = async (ctx) => { const token = (await ctx.request.formData()).get('cf-turnstile-response'); // 用 ctx.env.TURNSTILE_SECRET 校验(与 Workers 模式一致) };

预放行模式(Invisible + 缓存令牌)

适合"提前验证、提交时直接用"的流程:页面加载时用 Invisible Widget 静默获取令牌,拿到令牌后再显示受保护的表单:

<div id="turnstile-precheck"></div> <form id="protected-form" style="display: none;"> <button type="submit">Submit</button> </form> <script src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit"></script> <script> let cachedToken = null; window.onload = () => { window.turnstile.render('#turnstile-precheck', { sitekey: 'YOUR_SITE_KEY', size: 'invisible', callback: (token) => { cachedToken = token; document.getElementById('protected-form').style.display = 'block'; } }); }; </script>

令牌过期自动刷新

let widgetId = window.turnstile.render('#container', { sitekey: 'YOUR_SITE_KEY', 'refresh-expired': 'manual', 'expired-callback': () => { console.log('Token expired, refreshing...'); window.turnstile.reset(widgetId); } });

十二、常见问题与排查清单

四条铁律(最容易踩的坑)

  1. ❌ 跳过服务端校验:仅客户端校验极易被绕过,必须在服务端调用 siteverify。
  2. ❌ 密钥泄漏到客户端secret只能存在于服务端(环境变量 / Secret 绑定),绝不能写入前端代码。
  3. ❌ 复用令牌:令牌单次有效,重复校验会报timeout-or-duplicate。每次提交应使用新令牌,出错时reset(widgetId)后重试。
  4. ❌ 忽略令牌过期:令牌 5 分钟过期,需处理expired-callback或启用refresh-expired: 'auto'

常见错误速查

错误现象原因解决办法
Widget 不渲染sitekey 错误、CSP 拦截、file://协议核对 sitekey;为 challenges.cloudflare.com 配置 CSP;用http://访问
timeout-or-duplicate令牌过期(>5 分钟)或复用生成新令牌,令牌缓存不要超过 5 分钟
invalid-input-secret密钥错误从 Dashboard 核对密钥与环境变量
missing-input-response令牌未随请求发送检查表单字段名是否为cf-turnstile-response

框架级陷阱

  • React:Widget 重挂载:状态变化导致组件重渲染时会丢失令牌。解决:用useRef保存 widgetId,仅渲染一次,卸载时remove()
  • React StrictMode:双重渲染:开发模式下 Widget 会渲染两次。解决:useEffect的清理函数中调用turnstile.remove()
  • Next.js:SSR 水合:服务端渲染时window.turnstile不存在。解决:组件加'use client',或动态导入并设ssr: false
  • SPA:导航不清理:切换路由会残留孤儿 Widget。解决:在卸载钩子中移除(VueonBeforeUnmount、ReactuseEffect清理函数)。

网络与安全

  • CSP 拦截:按第五节添加script-srcframe-src指令。
  • IP 转发:确保拿到的是客户端真实 IP——Workers 中取CF-Connecting-IP;自建代理场景取X-Forwarded-For的第一项:request.headers.get('X-Forwarded-For')?.split(',')[0]
  • CORS(siteverify)禁止从浏览器直接调用 siteverify(会触发 CORS 且暴露密钥)。正确做法是:浏览器 → 你的后端 → siteverify。

调试三板斧

  1. 控制台日志:把各回调都打出来,观察令牌/错误/过期事件流:
window.turnstile.render('#container', { sitekey: 'YOUR_SITE_KEY', callback: (token) => console.log('✓ Token:', token), 'error-callback': (code) => console.error('✗ Error:', code), 'expired-callback': () => console.warn('⏱ Expired'), 'timeout-callback': () => console.warn('⏱ Timeout') });
  1. 检查令牌状态
const token = window.turnstile.getResponse(widgetId); console.log('Token:', token || 'NOT READY'); console.log('Expired:', window.turnstile.isExpired(widgetId));
  1. Network 面板:确认api.js返回 200、检查 siteverify 请求/响应、留意 4xx/5xx。

常见配置错误

  • 密钥配对错误:sitekey 与 secret 必须来自 Dashboard 中的同一个 Widget
  • 测试密钥用于生产:务必用环境变量按环境切换密钥;
  • 缺少环境变量:服务端TURNSTILE_SECRET未定义会导致校验直接失败。可在.env配置后用console.log('Secret loaded:', !!process.env.TURNSTILE_SECRET)验证加载情况。

十三、深入阅读

Turnstile 参考模块由五份文档组成,本文是对入口文档的完整展开,按以下顺序阅读可获得从配置到原理的完整链路:

  1. configuration.md —— 环境配置、Widget 选项、脚本加载方式;
  2. api.md —— 客户端 JavaScript API、siteverify 端点、TypeScript 类型;
  3. patterns.md —— 表单集成、框架示例、校验模式;
  4. gotchas.md —— 常见错误、调试技巧与限制说明。

若需要把 Turnstile 与 WAF、Bot Management、API Shield 等其他安全产品组合成整体防护方案,可回到 cloudflare-deploy Skill 的安全决策树按需选择对应参考模块。

【免费下载链接】skillsSkills Catalog for Codex项目地址: https://gitcode.com/GitHub_Trending/skills4/skills

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

SSM就业平台:岗位智能匹配与MySQL索引优化实战

简介&#xff1a;本资源是一套完整的毕业设计级学生就业服务平台实现方案&#xff0c;面向计算机专业本科生、Java初学者及SSM框架学习者&#xff0c;解决高校学生求职与企业招聘信息不对称、流程管理低效等实际问题。压缩包含867个文件&#xff0c;总计52.83MB&#xff0c;涵盖…

作者头像 李华
网站建设 2026/9/12 22:01:12

遥感影像地块分割全流程优化:预处理-建模-后处理抗干扰闭环

简介&#xff1a;本资源为2021年MathorCup高校数学建模挑战赛大数据竞赛B题「遥感地块分割」国家一等奖获奖作品完整技术包&#xff0c;面向数学建模参赛学生、遥感图像处理初学者及深度学习实践者。方案基于tif遥感影像与png标注图&#xff0c;集成数据预处理、U-Net模型训练、…

作者头像 李华
网站建设 2026/9/12 21:57:21

51单片机+Proteus交通灯仿真:定时器与状态机实践

简介&#xff1a;基于51单片机实现的交通灯Proteus仿真资源&#xff0c;面向单片机初学者与课程设计、电子竞赛备赛人群&#xff0c;重点演示了含直行、左转、黄灯过渡及人行道联动的标准十字路口时序控制。运行流程为南北方向直行绿灯40秒、黄灯5秒、左转绿灯20秒、黄灯5秒后切…

作者头像 李华
网站建设 2026/9/12 21:57:11

基于PLC的双容水箱液位控制系统设计与PID优化

1. 项目背景与系统概述 在工业自动化控制领域&#xff0c;液位控制一直是过程控制中的经典课题。双容水箱作为典型的二阶系统&#xff0c;其液位控制问题涵盖了工业生产中常见的时滞、耦合和非线性特性。我最近完成了一个基于S7-200 PLC和组态王的双容水箱液位控制系统设计项目…

作者头像 李华
网站建设 2026/9/12 21:55:39

text-to-cad:工程语义驱动的参数化建模技术

1. 什么是text-to-cad&#xff1a;不是“文字变图纸”&#xff0c;而是工程语义的精准翻译你搜“text-to-cad”时&#xff0c;看到的大多是零散提问——“cad下载”“cad画直线显示2.1616e”“solidworks导入step”“cad不用安装版本”……这些看似杂乱的关键词&#xff0c;恰恰…

作者头像 李华