分析 WordPress `_doing_ajax()` 函数的源码:如何判断当前请求是否为 AJAX 请求。

各位观众,下午好!今天咱们来聊聊 WordPress 里面的“侦察兵”—— _doing_ajax() 函数。这家伙专门负责判断当前是不是 AJAX 请求,扮演着一个至关重要的角色。咱们就来深入剖析一下它的源码,看看它是怎么“一眼识破” AJAX 请求的。

第一幕:初识 _doing_ajax()

首先,让我们来看看这个函数的真面目。在 WordPress 源码中(通常位于 wp-includes/functions.php 附近),你会找到类似这样的代码:

function _doing_ajax() {
    /**
     * Filters whether the current request is an AJAX request.
     *
     * @since 2.5.0
     *
     * @param bool $doing_ajax Whether the current request is an AJAX request.
     */
    return apply_filters( 'doing_ajax', defined( 'DOING_AJAX' ) && DOING_AJAX );
}

是不是感觉有点短?别被它的简洁外表迷惑,它可是个“老油条”了。它的核心逻辑其实就藏在 return 语句里。

第二幕:抽丝剥茧,步步为营

咱们把 return 语句拆解一下:

  1. defined( 'DOING_AJAX' ): 这个部分负责检查一个名为 DOING_AJAX 的常量是否已经被定义。defined() 是一个 PHP 函数,用来判断常量是否存在。如果 DOING_AJAX 已经被定义,它就返回 true,否则返回 false

  2. DOING_AJAX: 如果上面的 defined() 返回 true,那么这里就直接使用 DOING_AJAX 常量的值。 这个值通常是 true

  3. defined( 'DOING_AJAX' ) && DOING_AJAX: 这部分利用 && (逻辑与) 操作符,只有当 DOING_AJAX 常量既被定义,并且它的值是真值 (true) 时,整个表达式的结果才会是 true。 否则,结果就是 false

  4. apply_filters( 'doing_ajax', ... ): 这一步非常关键! WordPress 的钩子机制在这里发挥作用。 apply_filters() 函数允许开发者通过 doing_ajax 过滤器来修改 _doing_ajax() 函数的返回值。 也就是说,即使前面的逻辑判断出不是 AJAX 请求,开发者仍然可以通过这个过滤器“强行”把它改成 AJAX 请求。

第三幕:DOING_AJAX 常量从何而来?

关键问题来了:DOING_AJAX 常量到底是谁定义的? 又是何时定义的呢?

答案通常藏在 wp-config.php 文件或者 AJAX 请求的处理脚本中。

  • 情况一:AJAX 请求处理脚本

    最常见的情况是,在处理 AJAX 请求的 PHP 脚本(比如你自定义的插件里的某个文件)的开头,会定义这个常量:

    define( 'DOING_AJAX', true );

    通过明确地定义 DOING_AJAX 常量,脚本就告诉 WordPress:“嘿,我正在处理一个 AJAX 请求!”

  • 情况二:wp-config.php(不太常见)

    虽然不常见,但也有可能在 wp-config.php 文件中定义 DOING_AJAX 常量。 这种情况通常是为了强制 WordPress 认为所有请求都是 AJAX 请求(非常不推荐,除非你有极其特殊的理由)。

第四幕:为什么要用常量?

你可能会问:为什么要用一个常量来标记 AJAX 请求,而不是用 $_SERVER 变量或者其他方式?

  1. 清晰明了: 使用常量 DOING_AJAX,代码的意图非常明确。 任何看到这段代码的人都能立刻明白:这里正在处理 AJAX 请求。

  2. 可控性: 常量的值在运行时不能被轻易修改(除非你用一些非常规手段)。这有助于确保 AJAX 请求的判断逻辑不会被意外篡改。

  3. 钩子机制: 结合 apply_filters() 函数,WordPress 提供了灵活的扩展性。 开发者可以根据自己的需求,通过 doing_ajax 过滤器来修改 AJAX 请求的判断逻辑。

第五幕:$_SERVER 变量也能判断 AJAX 吗?

当然可以! 实际上,在某些情况下,开发者可能会使用 $_SERVER 变量来辅助判断 AJAX 请求。 常见的做法是检查 $_SERVER['HTTP_X_REQUESTED_WITH'] 变量。

  • $_SERVER['HTTP_X_REQUESTED_WITH']: 这个变量通常由 JavaScript 的 AJAX 库(比如 jQuery)设置。 当使用 jQuery 发送 AJAX 请求时,它会自动添加一个名为 X-Requested-With 的 HTTP 头,其值为 XMLHttpRequest

你可以这样判断:

if ( ! defined( 'DOING_AJAX' ) && isset( $_SERVER['HTTP_X_REQUESTED_WITH'] ) && strtolower( $_SERVER['HTTP_X_REQUESTED_WITH'] ) === 'xmlhttprequest' ) {
    define( 'DOING_AJAX', true );
}

这段代码的意思是:如果 DOING_AJAX 常量还没有被定义,并且 HTTP_X_REQUESTED_WITH 变量存在,并且它的值是 XMLHttpRequest(忽略大小写),那么就定义 DOING_AJAX 常量为 true

那么,为什么 WordPress 官方不直接使用 $_SERVER 变量呢?

  1. 可靠性$_SERVER['HTTP_X_REQUESTED_WITH'] 变量并非总是可靠的。 有些浏览器或客户端可能会篡改或删除这个 HTTP 头。 因此,依赖它来判断 AJAX 请求可能会导致误判。

  2. 安全性: 依赖客户端提供的 HTTP 头进行判断,存在一定的安全风险。 恶意用户可以伪造 X-Requested-With 头,从而绕过一些安全检查。

  3. 控制权: 通过 DOING_AJAX 常量,WordPress 应用程序可以更明确地控制 AJAX 请求的判断逻辑。 开发者可以在任何地方定义这个常量,而不需要依赖客户端的 HTTP 头。

第六幕:实战演练

让我们来看几个实际的例子,演示如何使用 _doing_ajax() 函数:

  • 例一:只在 AJAX 请求时执行特定代码

    if ( _doing_ajax() ) {
        // 只有在 AJAX 请求时才执行的代码
        $data = array( 'message' => 'Hello from AJAX!' );
        wp_send_json( $data ); // 发送 JSON 响应
    } else {
        // 非 AJAX 请求时执行的代码
        echo 'This is not an AJAX request.';
    }
  • 例二:根据 AJAX 请求与否加载不同的模板

    if ( _doing_ajax() ) {
        // 加载 AJAX 模板
        get_template_part( 'template-parts/ajax-content' );
    } else {
        // 加载普通模板
        get_template_part( 'template-parts/normal-content' );
    }
  • 例三:使用 doing_ajax 过滤器

    add_filter( 'doing_ajax', 'my_custom_ajax_check' );
    
    function my_custom_ajax_check( $is_ajax ) {
        // 自定义 AJAX 请求判断逻辑
        if ( isset( $_GET['custom_ajax'] ) && $_GET['custom_ajax'] === 'true' ) {
            return true; // 如果 URL 中有 custom_ajax=true,则认为是 AJAX 请求
        }
        return $is_ajax; // 否则,使用默认的判断逻辑
    }

第七幕:总结与思考

_doing_ajax() 函数是 WordPress 中判断 AJAX 请求的重要工具。 它通过检查 DOING_AJAX 常量是否存在,并结合 doing_ajax 过滤器,提供了一种灵活且可控的机制来识别 AJAX 请求。

特性 描述
核心机制 检查 DOING_AJAX 常量是否存在
扩展性 通过 doing_ajax 过滤器允许开发者自定义 AJAX 请求判断逻辑
可靠性 依赖 DOING_AJAX 常量,避免了直接依赖 $_SERVER 变量可能带来的问题
应用场景 根据 AJAX 请求与否执行不同的代码,加载不同的模板,进行不同的安全检查等
安全性 使用常量比直接依赖 $_SERVER 变量更安全,因为常量的值不容易被篡改。

在实际开发中,你应该始终使用 _doing_ajax() 函数来判断 AJAX 请求,而不是直接依赖 $_SERVER 变量。 这样可以提高代码的可靠性、安全性和可维护性。

记住,_doing_ajax() 就像一个经验丰富的侦察兵,它能帮助你的 WordPress 应用准确地识别 AJAX 请求,从而做出正确的决策。 希望今天的讲解能帮助你更好地理解 WordPress 的 AJAX 处理机制。 下次再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注