单纯靠User-Agent过滤无效,ThinkPHP 8.0应使用request()->header('user-agent')安全获取UA,结合stripos()白名单匹配、日志记录与限流,再通过前端JS行为打标(如X-Requested-With、Referer、自定义header)实现协同反爬。

单纯靠 User-Agent 过滤根本挡不住真实爬虫,也救不了被压垮的服务器;真正起效的是行为识别 + 渲染层协同,而 ThinkPHP 8.0 的中间件和钩子机制刚好能低成本落地。
ThinkPHP 8.0 中间件里怎么安全取 UA 并做轻量过滤
别在控制器里写 $_SERVER['HTTP_USER_AGENT'] —— Swoole 或 FastCGI 下它可能为空,且无法兼容 CLI 模式下的请求模拟。必须用框架封装好的接口:
-
request()->header('user-agent')是唯一可靠方式,TP8 已统一处理不同 SAPI 场景 - 白名单配置必须放
app/extra/spider.php,内容为return ['Chrome', 'Firefox', 'Mobile Safari', 'WeChat'];,避免每次请求查 DB - 匹配用
stripos(),不是===或正则全匹配:合法 UA 变体极多,比如Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15里只含Mobile Safari字段 - 对空字符串、纯数字(如
123456)、或含python-requests/curl/httpie的 UA,记录日志并触发RateLimit::oncePerMinute(3),不直接 halt()
为什么 JS 混淆渲染会让爬虫“看起来很像人”,但 TP 后端反而更难防
混淆后的 JS 能绕过基础 UA 检测,但它暴露了更关键的行为特征:页面加载后执行加密逻辑、携带动态生成的 sign 或 token、依赖 document.cookie 和 performance.now() 等浏览器 API。这些恰恰是 TP 后端可验证的硬指标:
- 检查
request()->cookie('thinkphp_token')是否存在且未过期——多数爬虫连 Cookie jar 都不维护 - 验证请求头中是否存在
X-Requested-With: XMLHttpRequest,真用户 JS 请求通常带这个,而静态爬虫常漏掉 - 比对
Referer是否来自你自己的域名,且路径是否匹配前端路由规则(如/detail/123→/list) - 若请求带
data-js-behavior自定义 header(由前端 JS 注入),说明已通过首屏 JS 执行校验,可跳过验证码
TP8 如何配合前端 JS 行为做反爬联动
不能只让后端猜,要让前端主动“打标”。在页面 HTML 底部注入一段最小化 JS:
用于端到端视频本地化流程的轻量编排器,路由至四个专注子技能——/wjs-transcribing-audio、/wjs-translating-subtitles...
立即学习“PHP免费学习笔记(深入)”;
if (window.performance && document.cookie.includes('thinkphp_token')) {
fetch('/api/behavior', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
ts: performance.now(),
ref: document.referrer,
js_ok: true
})
});
}
后端对应写一个轻量接口 app/controller/Api/Behavior.php,只存 Redis 记录(key 为 session_id,value 为 timestamp),有效期 5 分钟。后续高风险操作(如导出、登录)前,先查这个 key 是否存在且距今
这种模式下,即使爬虫伪造了 UA、绕过了 Referer,只要没执行 JS 或没带 Cookie,就卡在行为验证这一步。而真正用户几乎无感知。
最易被忽略的点:TP8 默认关闭 session.auto_start,如果前端 JS 依赖 thinkphp_token 但后端没开启会话驱动,整个行为链就断了。务必确认 config/session.php 中 'type' => 'file'(或 redis)且 'auto_start' => true 已启用。


















