详解 WordPress `is_rest_api_request()` 函数的源码:如何判断当前请求是否为 REST API。

各位观众老爷,早上好! 今天给大家带来的脱口秀啊不是,技术讲座,主题是“WordPress is_rest_api_request() 函数源码大揭秘:如何像福尔摩斯一样洞悉REST API请求”。准备好了吗?咱们这就开始!

开场白:REST API,你逃不出我的手掌心!

在WordPress的世界里,REST API 就像一个神秘的特工,它穿梭于各种请求之间,执行着各种任务。有时候我们需要像福尔摩斯一样,一眼就识别出它——判断当前请求是不是一个 REST API 请求。而 WordPress 提供了一个非常实用的工具,那就是 is_rest_api_request() 函数。但是,这个函数背后的逻辑是什么?它是如何工作的呢?今天,咱们就来扒一扒它的源码,看看它到底有什么秘密。

第一幕:is_rest_api_request() 函数的定义和基本用法

首先,我们来看看 is_rest_api_request() 函数的基本定义和用法。这个函数位于 wp-includes/functions.php 文件中(具体位置可能因 WordPress 版本而异,但通常都在这个目录下)。

/**
 * Determines whether the current request is a REST API request.
 *
 * @since 4.4.0
 *
 * @global WP_REST_Server $wp_rest_server REST server instance.
 *
 * @return bool True if it's a REST API request, false otherwise.
 */
function is_rest_api_request() {
    global $wp_rest_server;

    if ( empty( $wp_rest_server ) ) {
        return false;
    }

    $prefix = rest_get_url_prefix();

    /*
     * Ensure that the rest_route constant is defined, and that it is not empty.
     * Ensure that the REST route is not prefixed with the home URL.
     */
    if ( defined( 'REST_REQUEST' ) && REST_REQUEST
        && defined( 'REST_ROUTE' ) && ! empty( REST_ROUTE )
        && 0 !== strpos( REST_ROUTE, home_url() )
    ) {
        return true;
    }

    // Check if rest_url() has been called.
    if ( defined( 'REST_API_REQUEST' ) && REST_API_REQUEST ) {
        return true;
    }

    // Check if the rest_route filter has been used.
    if ( ! empty( $GLOBALS['wp_rest_internal_server'] ) ) {
        return true;
    }

    /*
     * Do the heavy lifting.  This is the most common method of determining
     * if a request is a REST request.
     */
    if ( defined( 'REST_REQUEST' ) && REST_REQUEST
        && isset( $_GET['rest_route'] )
        && strpos( $_GET['rest_route'], '/' . $prefix, 1 ) === 1
    ) {
        return true;
    }

    /*
     * Check if the request is for a REST API endpoint.
     * This is usually set by the rewrite rules.
     */
    if ( isset( $_SERVER['REQUEST_URI'] ) && strpos( $_SERVER['REQUEST_URI'], '/' . $prefix . '/' ) !== false ) {
        return true;
    }

    return false;
}

这个函数返回一个布尔值:true 表示当前请求是 REST API 请求,false 表示不是。

基本用法示例:

if ( is_rest_api_request() ) {
    // 这是一个 REST API 请求,执行相应的操作
    echo '恭喜你,抓到一只 REST API!';
} else {
    // 这不是一个 REST API 请求,执行其他操作
    echo '抱歉,这不是你要找的 REST API。';
}

第二幕:源码剖析,步步惊心

现在,我们来深入研究 is_rest_api_request() 函数的源码,看看它是如何判断一个请求是否为 REST API 请求的。

  1. 检查 $wp_rest_server 全局变量:

    global $wp_rest_server;
    
    if ( empty( $wp_rest_server ) ) {
    return false;
    }

    首先,函数会检查全局变量 $wp_rest_server 是否为空。这个变量是 WP_REST_Server 类的实例,只有在 WordPress 加载了 REST API 之后才会存在。如果为空,说明 REST API 还没有被初始化,那么肯定不是 REST API 请求,直接返回 false

  2. 检查 REST_REQUESTREST_ROUTE 常量:

    if ( defined( 'REST_REQUEST' ) && REST_REQUEST
    && defined( 'REST_ROUTE' ) && ! empty( REST_ROUTE )
    && 0 !== strpos( REST_ROUTE, home_url() )
    ) {
    return true;
    }

    这一步检查了两个常量:REST_REQUESTREST_ROUTE

    • REST_REQUEST:这是一个布尔常量,用于标记当前请求是否为 REST API 请求。
    • REST_ROUTE:这是一个字符串常量,用于存储 REST API 的路由。

    只有当 REST_REQUESTtrueREST_ROUTE 被定义且不为空,并且 REST_ROUTE 不以网站首页 URL 开头时,函数才会返回 truehome_url() 的检查是为了避免与网站首页的路由冲突。

  3. 检查 REST_API_REQUEST 常量:

    // Check if rest_url() has been called.
    if ( defined( 'REST_API_REQUEST' ) && REST_API_REQUEST ) {
    return true;
    }

    这个检查是用来判断 rest_url() 函数是否被调用。 rest_url() 函数在生成 REST API 的 URL 时会定义 REST_API_REQUEST 常量,如果这个常量被定义并且值为 true,则说明这是一个 REST API 请求。

  4. 检查 $GLOBALS['wp_rest_internal_server'] 变量:

    // Check if the rest_route filter has been used.
    if ( ! empty( $GLOBALS['wp_rest_internal_server'] ) ) {
    return true;
    }

    这个检查是用来判断 rest_route 过滤器是否被使用。这个过滤器允许开发者修改 REST API 的路由。如果 $GLOBALS['wp_rest_internal_server'] 变量不为空,则说明 rest_route 过滤器已经被使用,这也暗示着这是一个 REST API 请求。

  5. 检查 $_GET['rest_route'] 参数:

    if ( defined( 'REST_REQUEST' ) && REST_REQUEST
    && isset( $_GET['rest_route'] )
    && strpos( $_GET['rest_route'], '/' . $prefix, 1 ) === 1
    ) {
    return true;
    }

    这一步检查了 $_GET 数组中是否存在 rest_route 参数,以及该参数的值是否以 REST API 的前缀开头。

    • $_GET['rest_route']:这是通过 GET 请求传递的 REST API 路由。
    • rest_get_url_prefix():这个函数返回 REST API 的 URL 前缀,默认为 wp-json

    只有当 REST_REQUESTtrue,并且 $_GET['rest_route'] 存在,并且以 REST API 的前缀开头时,函数才会返回 truestrpos() 函数的第三个参数 1 表示从字符串的第二个字符开始查找,避免匹配到根目录。

  6. 检查 $_SERVER['REQUEST_URI'] 参数:

    if ( isset( $_SERVER['REQUEST_URI'] ) && strpos( $_SERVER['REQUEST_URI'], '/' . $prefix . '/' ) !== false ) {
    return true;
    }

    这一步检查了 $_SERVER 数组中的 REQUEST_URI 参数,该参数包含了请求的 URL。函数会检查 REQUEST_URI 中是否包含 REST API 的前缀。如果包含,则认为这是一个 REST API 请求。

  7. 默认返回 false

    return false;

    如果以上所有条件都不满足,那么函数最终会返回 false,表示这不是一个 REST API 请求。

第三幕:关键函数的解析

is_rest_api_request() 函数中,有两个关键的辅助函数:rest_get_url_prefix()home_url()。我们来简单了解一下它们的作用。

  • rest_get_url_prefix()

    这个函数用于获取 REST API 的 URL 前缀。默认情况下,这个前缀是 wp-json。但是,可以通过 rest_url_prefix 过滤器来修改这个前缀。

    /**
     * Gets the rest url prefix.
     *
     * @since 4.4.0
     *
     * @return string URL prefix.
     */
    function rest_get_url_prefix() {
        /**
         * Filters the rest url prefix.
         *
         * @since 4.4.0
         *
         * @param string $rest_prefix The REST API URL prefix.
         */
        return apply_filters( 'rest_url_prefix', 'wp-json' );
    }

    示例:自定义 REST API 前缀

    add_filter( 'rest_url_prefix', 'my_custom_rest_prefix' );
    
    function my_custom_rest_prefix( $prefix ) {
        return 'api'; // 将 REST API 前缀修改为 'api'
    }

    这样,你的 REST API URL 就会变成 yourdomain.com/api/your-endpoint

  • home_url()

    这个函数用于获取网站的首页 URL。它会返回你 WordPress 安装的根目录的 URL。这个函数在 is_rest_api_request() 中用于防止 REST API 的路由与网站首页的路由冲突。

第四幕:代码示例,实战演练

为了更好地理解 is_rest_api_request() 函数的使用,我们来看几个具体的代码示例。

示例 1:在主题 functions.php 文件中判断 REST API 请求

add_action( 'init', 'my_theme_check_rest_api' );

function my_theme_check_rest_api() {
    if ( is_rest_api_request() ) {
        // 这是一个 REST API 请求
        // 可以在这里执行一些特定的操作,例如加载特定的 CSS 或 JavaScript 文件
        add_action( 'wp_enqueue_scripts', 'my_theme_enqueue_rest_api_scripts' );
    }
}

function my_theme_enqueue_rest_api_scripts() {
    wp_enqueue_style( 'my-rest-api-style', get_template_directory_uri() . '/css/rest-api.css' );
    wp_enqueue_script( 'my-rest-api-script', get_template_directory_uri() . '/js/rest-api.js', array( 'jquery' ), '1.0', true );
}

在这个示例中,我们在 init 钩子上添加了一个函数 my_theme_check_rest_api()。这个函数会检查当前请求是否为 REST API 请求。如果是,它会添加一个 wp_enqueue_scripts 钩子,用于加载特定的 CSS 和 JavaScript 文件。

示例 2:在插件中使用 is_rest_api_request() 函数

add_action( 'plugins_loaded', 'my_plugin_check_rest_api' );

function my_plugin_check_rest_api() {
    if ( is_rest_api_request() ) {
        // 这是一个 REST API 请求
        // 可以在这里执行一些特定的操作,例如注册 REST API 路由
        add_action( 'rest_api_init', 'my_plugin_register_rest_route' );
    }
}

function my_plugin_register_rest_route() {
    register_rest_route( 'my-plugin/v1', '/data', array(
        'methods'  => 'GET',
        'callback' => 'my_plugin_get_data',
    ) );
}

function my_plugin_get_data( WP_REST_Request $request ) {
    // 处理 REST API 请求并返回数据
    $data = array(
        'message' => 'Hello from my plugin!',
    );

    return rest_ensure_response( $data );
}

在这个示例中,我们在 plugins_loaded 钩子上添加了一个函数 my_plugin_check_rest_api()。这个函数会检查当前请求是否为 REST API 请求。如果是,它会添加一个 rest_api_init 钩子,用于注册 REST API 路由。

第五幕:注意事项与常见问题

在使用 is_rest_api_request() 函数时,需要注意以下几点:

  • 钩子函数的位置: 确保在适当的钩子函数中使用 is_rest_api_request() 函数。例如,如果你需要在主题或插件初始化时执行某些操作,可以使用 initplugins_loaded 钩子。
  • 缓存问题: 有些缓存插件可能会影响 is_rest_api_request() 函数的判断结果。如果遇到问题,可以尝试禁用缓存插件或者配置缓存规则,排除 REST API 请求。
  • 自定义路由: 如果你使用了自定义的 REST API 路由,需要确保这些路由能够被正确识别。你可以使用 rest_url_prefix 过滤器来修改 REST API 的 URL 前缀,或者手动检查 $_SERVER['REQUEST_URI'] 参数。

常见问题:

  1. is_rest_api_request() 函数总是返回 false

    • 检查是否正确初始化了 REST API。
    • 检查是否有缓存插件干扰。
    • 检查 URL 是否正确,是否包含 REST API 前缀。
  2. 如何调试 is_rest_api_request() 函数?

    • 使用 var_dump()error_log() 函数输出相关变量的值,例如 $_SERVER['REQUEST_URI']$_GET['rest_route'] 等。
    • 使用 WordPress 的调试模式,查看是否有错误或警告信息。

第六幕:进阶技巧,更上一层楼

除了 is_rest_api_request() 函数之外,还有一些其他的技巧可以帮助你更好地处理 REST API 请求。

  • 使用 WP_REST_Request 类:

    WP_REST_Request 类是 WordPress REST API 中用于处理请求的类。你可以使用这个类来获取请求的参数、头部信息等。

    function my_plugin_get_data( WP_REST_Request $request ) {
        $param1 = $request->get_param( 'param1' );
        $header = $request->get_header( 'X-My-Header' );
    
        // ...
    }
  • 使用 rest_ensure_response() 函数:

    rest_ensure_response() 函数用于确保 REST API 的响应是一个 WP_REST_Response 对象。

    function my_plugin_get_data( WP_REST_Request $request ) {
        $data = array(
            'message' => 'Hello from my plugin!',
        );
    
        return rest_ensure_response( $data );
    }
  • 自定义 REST API 中间件:

    你可以通过过滤器和钩子函数,自定义 REST API 的中间件,用于执行一些通用的操作,例如身份验证、授权、日志记录等。

表格总结:is_rest_api_request() 函数判断依据

判断依据 说明
$wp_rest_server 全局变量是否为空 检查 REST API 是否已初始化,如果未初始化,则不是 REST API 请求。
REST_REQUESTREST_ROUTE 常量是否定义且符合条件 检查 REST_REQUEST 是否为 trueREST_ROUTE 是否定义且不为空,且不以网站首页 URL 开头。
REST_API_REQUEST 常量是否定义且为 true 检查 rest_url() 函数是否被调用,如果调用了,则该常量会被定义且为 true
$GLOBALS['wp_rest_internal_server'] 是否为空 检查 rest_route 过滤器是否被使用,如果被使用了,则该变量不为空。
$_GET['rest_route'] 参数是否存在且符合条件 检查 GET 请求中是否存在 rest_route 参数,并且该参数的值是否以 REST API 的前缀开头。
$_SERVER['REQUEST_URI'] 参数是否包含 REST API 前缀 检查请求的 URL 中是否包含 REST API 的前缀,例如 /wp-json//api/

结语:REST API,尽在掌握!

通过今天的讲座,相信大家对 WordPress 的 is_rest_api_request() 函数有了更深入的了解。掌握了这个函数,你就能够在 WordPress 中轻松地判断当前请求是否为 REST API 请求,并根据需要执行相应的操作。希望今天的分享对大家有所帮助! 谢谢大家!

发表回复

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