You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何判断PHP脚本是AJAX调用还是浏览器访问?原方法失效求替代方案

区分PHP脚本的AJAX调用与直接访问(无需额外参数)

我完全理解你的困扰——本来依赖X-Requested-With: XMLHttpRequest这个请求头是区分AJAX和直接访问的常规操作,但在特定环境下失效确实让人头疼,而且你还不想额外加GET/POST参数,这个需求非常合理。

首先,我们得先排查下为什么原本的方法在PHP 7.1.11 + Chrome 63环境下失效,常见原因有这几个:

  • 前端请求未自动添加该头:只有jQuery、Axios这类封装好的AJAX库会自动设置X-Requested-With头,原生XMLHttpRequest或fetch API默认是不会加的。如果你的前端用的是原生请求,需要手动调用setRequestHeader('X-Requested-With', 'XMLHttpRequest')才行。
  • 服务器配置过滤了请求头:比如Apache或Nginx的配置中,可能没有把这个自定义头传递给PHP的$_SERVER变量。你可以先在PHP里打印var_dump($_SERVER),看看有没有HTTP_X_REQUESTED_WITH这个键,确认是否是服务器端的问题。
  • 浏览器/插件限制:Chrome 63的某些隐私设置或第三方插件可能会阻止这类自定义请求头的发送,不过这种情况相对少见。

接下来,给你几个无需额外GET/POST参数的替代区分方案:

1. 检查Accept请求头

AJAX请求通常会明确指定接受的数据类型(比如JSON、XML),而浏览器直接访问一般默认接受text/html。你可以在PHP中这样判断:

$isAjax = false;
if (!empty($_SERVER['HTTP_ACCEPT'])) {
    // 匹配常见的AJAX接受类型
    $ajaxAcceptTypes = ['application/json', 'application/xml', 'text/json', 'text/xml'];
    foreach ($ajaxAcceptTypes as $type) {
        if (strpos($_SERVER['HTTP_ACCEPT'], $type) !== false) {
            $isAjax = true;
            break;
        }
    }
}

⚠️ 注意:这个方法不是100%绝对(比如有些AJAX也可能请求HTML,或者浏览器插件会修改Accept头),但结合业务场景可以作为有效辅助。

2. 自定义专属请求头(最可靠)

如果你能控制前端的AJAX请求逻辑,可以自定义一个专属的请求头(不用加在URL或POST参数里),比如X-Is-Ajax: 1,然后在PHP中检查:

$isAjax = isset($_SERVER['HTTP_X_IS_AJAX']) && $_SERVER['HTTP_X_IS_AJAX'] === '1';

前端原生XMLHttpRequest的设置示例:

const xhr = new XMLHttpRequest();
xhr.open('GET', 'your-script.php');
xhr.setRequestHeader('X-Is-Ajax', '1');
xhr.send();

这种方式完全不受环境影响,是最稳定的区分方法,而且符合你“无需额外参数”的要求。

3. 结合HTTP_REFERER辅助判断

如果是同域下的AJAX请求,HTTP_REFERER通常会指向发起请求的页面URL;而直接访问脚本时,HTTP_REFERER大概率为空(或者不是本站域名)。你可以这样辅助验证:

$isSameDomainReferer = false;
if (!empty($_SERVER['HTTP_REFERER'])) {
    $refererHost = parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST);
    $currentHost = parse_url($_SERVER['HTTP_HOST'], PHP_URL_HOST);
    $isSameDomainReferer = ($refererHost === $currentHost);
}
// 结合Accept头或其他条件一起判断
$isAjax = $isSameDomainReferer && strpos($_SERVER['HTTP_ACCEPT'], 'application/json') !== false;

⚠️ 注意:HTTP_REFERER可以被浏览器或用户手动修改,所以只能作为辅助条件,不能单独依赖。

4. 检查请求的Content-Type(针对POST请求)

如果你的AJAX是POST请求,通常会使用application/json或application/x-www-form-urlencoded(后者和表单提交一致,但前者是AJAX常用的)。可以这样判断:

$isAjaxPost = false;
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_SERVER['HTTP_CONTENT_TYPE'])) {
    $isAjaxPost = strpos($_SERVER['HTTP_CONTENT_TYPE'], 'application/json') !== false;
}

综合来看,自定义专属请求头是最推荐的方案,只要能控制前端,就能100%可靠地区分;如果无法修改前端,就结合Accept头、Referer等多个条件来提高判断的准确性。

内容的提问来源于stack exchange,提问作者Mawg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:35:37