解析 WordPress `rest_url()` 函数的源码:如何动态生成 REST API 的端点 URL。

各位观众,晚上好! 今天咱们来聊聊 WordPress 里一个相当重要,但也容易被忽略的函数:rest_url()。 它就像一个魔法师,能帮你动态生成 REST API 的端点 URL。 别怕,听起来玄乎,其实挺简单。

开场白:REST API 的重要性

在现代 Web 开发中,REST API 扮演着至关重要的角色。 它们就像不同系统之间的桥梁,允许应用程序以标准化的方式交换数据。 WordPress 也不例外,它内置了强大的 REST API,允许开发者访问和操作 WordPress 的各种功能,例如文章、页面、用户等等。

rest_url():REST API 的 URL 生成器

rest_url() 函数就是负责生成这些 API 端点 URL 的关键。 简单来说,它能帮你把一个相对路径变成一个完整的、可访问的 URL。 想象一下,你告诉它 "wp/v2/posts",它就能帮你生成类似 https://your-domain.com/wp-json/wp/v2/posts 的 URL。

源码解析:拨开迷雾见真章

咱们直接上代码,看看 rest_url() 到底是怎么工作的。 它的定义在 wp-includes/rest-api.php 文件里。

/**
 * Retrieves the REST URL.
 *
 * @since 4.4.0
 *
 * @param string $path   Optional. REST route. Default empty.
 * @param string $scheme Optional. Sanitization scheme. Default 'rest'.
 * @return string REST URL.
 */
function rest_url( $path = '', $scheme = 'rest' ) {
    if ( defined( 'REST_REQUEST' ) && REST_REQUEST && ! is_admin() ) {
        $url = home_url( '', $scheme );
    } else {
        $url = get_rest_url( null, $path, $scheme );
    }

    return $url;
}

这段代码的核心逻辑是:

  1. 检查 REST_REQUEST 常量: 如果定义了 REST_REQUEST 并且值为 true,并且不是在后台管理界面,那么就直接使用 home_url() 函数来构建 URL。 home_url() 返回的是站点的首页 URL。 这种情况通常发生在 REST API 请求的上下文中。
  2. 否则,使用 get_rest_url() 函数: 如果 REST_REQUEST 没有定义或者值为 false,或者是在后台管理界面,那么就使用 get_rest_url() 函数来构建 URL。 get_rest_url() 才是真正负责生成 REST API URL 的主力函数。

深入 get_rest_url():幕后英雄

get_rest_url() 函数稍微复杂一些,但它才是真正干活的。

/**
 * Retrieves the REST base URL.
 *
 * @since 4.4.0
 *
 * @param int|null   $blog_id Optional. Blog ID. Default null.
 * @param string $path    Optional. REST route. Default empty.
 * @param string $scheme  Optional. Sanitization scheme. Default 'rest'.
 * @return string REST base URL, with endpoint.
 */
function get_rest_url( $blog_id = null, $path = '/', $scheme = 'rest' ) {
    if ( empty( $blog_id ) ) {
        $url = get_option( 'siteurl' );
    } else {
        switch_to_blog( $blog_id );
        $url = get_option( 'siteurl' );
        restore_current_blog();
    }

    if ( 'relative' === $scheme ) {
        $url = wp_make_link_relative( $url );
    } else {
        $url = set_url_scheme( $url, $scheme );
    }

    $rest_prefix = trailingslashit( rest_get_url_prefix() );

    if ( $path && is_string( $path ) ) {
        $url .= $rest_prefix . ltrim( $path, '/' );
    } else {
        $url .= $rest_prefix;
    }

    return $url;
}

这个函数的主要步骤如下:

  1. 获取站点 URL: 首先,它会根据 $blog_id 参数获取站点的 URL。 如果 $blog_id 为空,则使用 get_option( 'siteurl' ) 获取当前站点的 URL。 如果 $blog_id 不为空,则会切换到指定的站点,获取 URL,然后再切换回当前站点。
  2. 处理 URL Scheme: 接下来,它会根据 $scheme 参数处理 URL 的 Scheme。 如果 $schemerelative,则使用 wp_make_link_relative() 函数将 URL 转换为相对路径。 否则,使用 set_url_scheme() 函数设置 URL 的 Scheme,默认为 rest,会根据当前站点的协议(http 或 https)来设置。
  3. 获取 REST 前缀: 然后,它会使用 rest_get_url_prefix() 函数获取 REST API 的 URL 前缀。 默认情况下,这个前缀是 /wp-json
  4. 拼接 URL: 最后,它会将站点 URL、REST 前缀和 $path 参数拼接起来,生成完整的 REST API URL。

rest_get_url_prefix():前缀的秘密

rest_get_url_prefix() 函数定义如下:

/**
 * Retrieves the REST URL prefix.
 *
 * @since 4.4.0
 *
 * @return string REST prefix.
 */
function rest_get_url_prefix() {
    /**
     * Filters the REST URL prefix.
     *
     * @since 4.4.0
     *
     * @param string $prefix URL prefix. Default 'wp-json'.
     */
    return apply_filters( 'rest_url_prefix', 'wp-json' );
}

这个函数很简单,它只是返回一个字符串 'wp-json',但它允许通过 rest_url_prefix 过滤器来修改这个前缀。 这意味着你可以自定义 REST API 的 URL 前缀,例如改成 /api/v1

用例演示:实战演练

光说不练假把式,咱们来几个实际的例子:

场景 代码 生成的 URL
获取文章列表的 URL rest_url( 'wp/v2/posts' ); https://your-domain.com/wp-json/wp/v2/posts
获取指定 ID 的文章的 URL rest_url( 'wp/v2/posts/123' ); https://your-domain.com/wp-json/wp/v2/posts/123
获取评论列表的 URL rest_url( 'wp/v2/comments' ); https://your-domain.com/wp-json/wp/v2/comments
获取用户列表的 URL rest_url( 'wp/v2/users' ); https://your-domain.com/wp-json/wp/v2/users
使用相对路径获取文章列表的 URL rest_url( 'wp/v2/posts', 'relative' ); /wp-json/wp/v2/posts (取决于你的站点配置)
使用自定义前缀获取文章列表的 URL (需要先使用过滤器修改 rest_url_prefix) rest_url( 'v1/posts' ); https://your-domain.com/api/v1/posts (假设你把前缀改成了 /api)
在后台获取文章列表的 URL 在后台页面执行 rest_url( 'wp/v2/posts' ); https://your-domain.com/wp-json/wp/v2/posts (即使定义了 REST_REQUEST 也是一样的)

自定义 REST API 前缀:让你的 API 更个性

如果你想自定义 REST API 的 URL 前缀,可以使用 rest_url_prefix 过滤器。 例如,你可以把前缀改成 /api

add_filter( 'rest_url_prefix', 'my_custom_rest_prefix' );

function my_custom_rest_prefix( $prefix ) {
    return 'api';
}

这段代码会将 REST API 的 URL 前缀修改为 /api。 之后,当你调用 rest_url( 'v1/posts' ); 时,生成的 URL 将会是 https://your-domain.com/api/v1/posts

REST_REQUEST 常量的作用:区分请求上下文

REST_REQUEST 常量用于区分当前的请求是否是 REST API 请求。 如果定义了 REST_REQUEST 并且值为 true,则表示当前的请求是一个 REST API 请求。 在这种情况下,rest_url() 函数会直接使用 home_url() 函数来构建 URL,而不会调用 get_rest_url() 函数。

这个常量的主要作用是优化性能。 在 REST API 请求的上下文中,可以直接使用 home_url() 函数来构建 URL,避免了调用 get_rest_url() 函数带来的额外开销。

需要注意的地方:坑和陷阱

  • 确保 REST API 已经启用: WordPress 的 REST API 默认是启用的,但如果你的站点使用了某些插件或主题,可能会禁用 REST API。 如果你发现 rest_url() 函数无法正常工作,首先要检查 REST API 是否已经启用。
  • 权限问题: 访问 REST API 需要相应的权限。 如果你没有足够的权限,可能会收到 401 Unauthorized 错误。
  • CORS 问题: 如果你的 REST API 接口被其他域名的网站调用,可能会遇到 CORS (Cross-Origin Resource Sharing) 问题。 你需要在服务器端配置 CORS 策略,允许跨域访问。
  • 缓存问题: 如果你的站点使用了缓存插件,可能会缓存 REST API 的响应。 这可能会导致数据不一致。 你需要配置缓存插件,使其正确处理 REST API 的请求。
  • URL Scheme: rest_url() 默认使用 rest 作为 URL Scheme。 这会自动根据站点的协议(http 或 https)来设置 URL 的 Scheme。 如果你需要生成相对路径的 URL,可以使用 relative 作为 URL Scheme。
  • 多站点环境: 在多站点环境中,get_rest_url() 函数可以根据 $blog_id 参数获取指定站点的 REST API URL。 如果 $blog_id 为空,则获取当前站点的 REST API URL。

总结:rest_url() 的价值

rest_url() 函数是 WordPress REST API 的一个重要组成部分。 它提供了一种简单而灵活的方式来生成 REST API 的端点 URL。 通过理解 rest_url() 函数的源码和用法,你可以更好地利用 WordPress REST API,构建强大的 Web 应用程序。

表格总结关键点

函数/常量 描述
rest_url() 用于生成 REST API 的端点 URL。 它会根据当前的请求上下文和参数,选择使用 home_url()get_rest_url() 函数来构建 URL。
get_rest_url() 负责生成 REST API 的 URL。 它会获取站点 URL、REST 前缀和路径,并将它们拼接起来,生成完整的 REST API URL。
rest_get_url_prefix() 用于获取 REST API 的 URL 前缀,默认为 /wp-json。 可以通过 rest_url_prefix 过滤器来修改这个前缀。
REST_REQUEST 一个常量,用于区分当前的请求是否是 REST API 请求。 如果定义了 REST_REQUEST 并且值为 true,则表示当前的请求是一个 REST API 请求。 在这种情况下,rest_url() 函数会直接使用 home_url() 函数来构建 URL,避免了调用 get_rest_url() 函数带来的额外开销。

希望今天的讲座能帮助你更好地理解 rest_url() 函数。 记住,理解源码是掌握技术的关键! 谢谢大家!

发表回复

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