HTTP_X_REQUESTED_WITH通常可用但不绝对可靠,因其可被伪造、跨域时可能丢失、JSONP场景下不存在,且受服务器配置(如Nginx需启用underscores_in_headers)和运行环境(如Swoole变量复用)影响。

直接用 $_SERVER['HTTP_X_REQUESTED_WITH'] 判断最常用,但不能全信——它可被伪造、跨域时可能丢失、JSONP 场景下根本不存在。
为什么 HTTP_X_REQUESTED_WITH 通常可用但不绝对可靠
jQuery、Axios(默认配置)、原生 XMLHttpRequest 在发请求时会自动带上 X-Requested-With: XMLHttpRequest 头,PHP 将其转为 $_SERVER['HTTP_X_REQUESTED_WITH'](注意中划线变下划线,大小写不敏感)。但以下情况会让这个判断失效:
- 前端用
fetch()且没手动设置headers: {'X-Requested-With': 'XMLHttpRequest'},默认不带该头 - 跨域请求中,若未显式声明
Access-Control-Allow-Headers: X-Requested-With,浏览器会过滤掉该头 - JSONP 请求本质是
<script>标签加载,压根没有 HTTP 头,$_SERVER['HTTP_X_REQUESTED_WITH']必然为空 - 攻击者或调试工具可随意伪造该头,仅靠它做权限控制有风险
isXmlHttpRequest() 在 Yaf 框架里怎么用
Yaf 提供了封装方法 Yaf_Request_Http::isXmlHttpRequest(),内部逻辑和手写判断一致,只是做了空值和大小写归一化处理:
// 在控制器中
$request = $this->getRequest();
if ($request instanceof Yaf_Request_Http && $request->isXmlHttpRequest()) {
// 处理 AJAX 响应,比如只输出 JSON
echo json_encode(['status' => 'ok']);
} else {
// 渲染完整 HTML 页面
$this->display('index.tpl');
}
注意:isXmlHttpRequest() 无参数,也不抛异常;它不解决跨域或 JSONP 场景,只是帮你少写几行 strtolower + isset。
立即学习“PHP免费学习笔记(深入)”;
当 HTTP_X_REQUESTED_WITH 不可用时,有哪些替代方案
不能只押宝一个头字段。实际项目中建议组合判断,优先级按可靠性排序:
- 检查
$_SERVER['HTTP_ACCEPT']是否包含application/json或text/javascript—— AJAX 请求常明确申明接受 JSON - 检查是否为 POST 且含特定参数,如
isset($_POST['ajax']) || isset($_GET['format']) && $_GET['format'] === 'json'(需配合业务约定) - 结合 Session 状态或 CSRF token 验证:非 AJAX 请求通常走完整表单流,token 存在且校验通过才允许继续
- 避免用
$_SERVER['HTTP_REFERER']判断——它易被禁用、跨站时为空、隐私模式下不可靠
最容易被忽略的边界点
真正上线后出问题的,往往不是主流程,而是这些细节:
- Apache + FastCGI 环境下,
HTTP_X_REQUESTED_WITH可能被重写模块拦截,需确认mod_rewrite规则里没误删自定义头 - Nginx 默认不透传带下划线的头,需显式配置
underscores_in_headers on;,否则$_SERVER['HTTP_X_REQUESTED_WITH']永远为空 - 如果用 Swoole 或 RoadRunner 这类常驻进程框架,
$_SERVER是复用的,务必确认每次请求都重置或隔离了该变量 - 移动端 WebView 或某些小程序容器发起的请求,可能完全不遵循标准头规则,得靠业务层埋点或 UA 特征辅助识别



















