在thinkphp 6中间件中应直接使用request()->isajax()或注入的$request->isajax()判断ajax请求,它基于x-requested-with头检测,安全可靠;避免使用未定义的is_ajax常量或input('ajax')等易伪造方式。

中间件里直接调用 request()->isAjax() 就行
ThinkPHP 6 的中间件中,request() 助手函数和注入的 Request 对象都支持 isAjax() 方法,它底层就是检测 HTTP_X_REQUESTED_WITH 头是否为 XMLHttpRequest,不依赖任何额外配置。不需要自己解析 $_SERVER 或手动读 header。
常见错误是试图在中间件里用 IS_AJAX 常量——这个常量只在控制器初始化阶段由框架定义,中间件执行时还没触发那步,直接用会报 undefined constant 错误。
-
request()->isAjax()是最简、最稳的方式,TP6 全版本兼容 - 若使用依赖注入(如
public function handle(Request $request, \Closure $next)),直接调用$request->isAjax() - 不要用
input('ajax')或检查 GET/POST 中的ajax参数——这容易被伪造,且 TP6 默认已弃用VAR_AJAX_SUBMIT配置
为什么 isAjax() 在中间件里有时返回 false
不是方法失效,而是请求头没传对。原生 fetch 或 XMLHttpRequest 默认不自动带 X-Requested-With,只有 jQuery 等老库才默认加。Chrome 从 2022 年起也逐步限制该 header 的自动注入。
前端必须显式设置:
fetch(url, { headers: { 'X-Requested-With': 'XMLHttpRequest' } })axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'- 原生
XMLHttpRequest要在open()后、send()前调用xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest')
漏掉这一步,isAjax() 必然返回 false,和框架无关。
需要兼容非标准 AJAX 请求?自己补 header 检测逻辑
有些场景(比如跨域上传、第三方 SDK 调用)无法控制 header,又必须走 AJAX 分支逻辑,那就得绕过 isAjax(),手动检查更宽松的条件:
- 检测
request()->header('content-type')是否含application/json或application/x-www-form-urlencoded - 检查
request()->url()是否匹配预设的 API 路由前缀(如/api/) - 结合
request()->isPost() || request()->isPut() || request()->isDelete()排除常规表单 GET
注意:这种判断不能替代安全校验,仅用于路由分发;敏感操作仍需 CSRF token 或签名验证,不能只靠“像不像 AJAX”来放行。
中间件里统计 AJAX 请求频次,别踩缓存并发坑
如果要在中间件里做限流或计数(比如记录每个 IP 每分钟调用次数),必须用原子操作,否则高并发下计数会丢失:
- ✅ 正确:
Cache::inc('ajax:count:'.$ip.':'.$route, 1, 60)—— Redis INCR 天然原子 - ❌ 错误:
$n = Cache::get($key); Cache::set($key, $n + 1, 60)—— 读-改-写非原子,两个请求同时读到 5,都会写 6 -
$route要标准化:用str_replace(['?', '#'], '', $request->url(true))去 query/hash,再转小写,避免/user?id=1和/user?id=2被算作不同接口 -
$ip别信$request->ip(),优先取$request->header('X-Real-IP', $request->ip())
真正难的从来不是“怎么写”,而是当几十个请求同一毫秒撞进来时,你的计数还准不准——这时候 Cache::inc() 是唯一能托底的方案。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











