分析 WordPress `WP_REST_Server` 类源码:REST API 请求处理与路由机制。

WordPress REST API 架构漫游:WP_REST_Server 类深度解析

大家好!欢迎来到今天的“WordPress REST API 架构漫游”讲座。今天,我们聚焦 WordPress REST API 的核心大脑——WP_REST_Server 类。我们将一起扒开它的源码,看看它是如何处理请求,以及如何进行路由的。

1. REST API 简介:别怕,它就是个搬运工

在深入代码之前,先简单回顾一下 REST API 的概念。简单来说,REST (Representational State Transfer) 是一种软件架构风格,它定义了一组约束,用于创建可扩展的网络服务。在 WordPress 的语境下,REST API 提供了一种标准的方式,通过 HTTP 请求(GET, POST, PUT, DELETE)来访问和操作 WordPress 数据,例如文章、用户、分类等等。

你可以把 REST API 想象成一个勤劳的搬运工,它负责把 WordPress 的数据从服务器搬运到你的客户端(比如你的手机 App 或 JavaScript 应用),然后再把客户端的修改搬运回服务器。

2. WP_REST_Server:REST API 的大脑

WP_REST_Server 类是 WordPress REST API 的核心。它负责接收 HTTP 请求,解析请求,调用相应的处理函数,然后将结果格式化后返回给客户端。

2.1 实例化和初始化

WP_REST_Server 类通常在 WordPress 初始化时被实例化,并存储在全局变量 $wp_rest_server 中。

global $wp_rest_server;
$wp_rest_server = new WP_REST_Server;

初始化主要涉及注册路由,我们稍后会详细讲解。

2.2 核心属性

  • $routes: 一个数组,存储着所有已注册的路由。每个路由都对应一个或多个处理函数。
  • $endpoints: 一个数组,缓存了已注册的 endpoint 信息,用于优化性能。
  • $request: WP_REST_Request 类的实例,代表当前的 HTTP 请求。
  • $response: WP_REST_Response 类的实例,代表将要返回给客户端的 HTTP 响应。

3. 请求处理流程:REST API 的一天

让我们模拟一个 REST API 请求,看看 WP_REST_Server 是如何处理的。假设我们发送一个 GET 请求到 /wp/v2/posts,以获取所有文章。

  1. 接收请求: WordPress 接收到 HTTP 请求,并确定这是一个 REST API 请求。通常,REST API 请求的 URL 会以 /wp-json/ 开头。

  2. 创建 WP_REST_Request 对象: WP_REST_Server 创建一个 WP_REST_Request 对象,用于封装请求的所有信息,包括请求方法 (GET, POST, etc.)、URL、请求头、请求参数等等。

    $request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
  3. 路由匹配: WP_REST_Server 遍历 $routes 数组,尝试找到与当前请求 URL 和请求方法匹配的路由。这就像警察拿着通缉令在人群中寻找罪犯一样。

  4. 调用处理函数: 如果找到匹配的路由,WP_REST_Server 会调用该路由对应的处理函数。处理函数负责执行实际的业务逻辑,比如从数据库中获取文章数据。

  5. 创建 WP_REST_Response 对象: 处理函数返回数据后,WP_REST_Server 创建一个 WP_REST_Response 对象,用于封装响应的所有信息,包括响应数据、HTTP 状态码、响应头等等。

    $response = new WP_REST_Response( $data, 200 ); // $data 是文章数据,200 是 HTTP 状态码
  6. 发送响应: WP_REST_ServerWP_REST_Response 对象转换为 JSON 格式,并通过 HTTP 协议发送给客户端。

4. 路由注册:告诉 REST API 去哪儿找吃的

路由注册是 REST API 的核心。它告诉 WP_REST_Server,当收到特定 URL 和请求方法的请求时,应该调用哪个处理函数。

WordPress 提供了一个函数 register_rest_route() 来注册路由。

/**
 * Registers a REST route.
 *
 * @param string   $namespace The namespace for the route.
 * @param string   $route     The REST route.
 * @param array    $args      Optional. An array of arguments to configure the route.
 * @param bool     $override  Optional. Whether to override existing routes. Default is false.
 * @return bool True on success, false on failure.
 */
function register_rest_route( $namespace, $route, $args = array(), $override = false ) {}
  • $namespace: 命名空间,用于区分不同的 API。例如,wp/v2 是 WordPress 核心 API 的命名空间。
  • $route: 路由的 URL。例如,posts
  • $args: 一个数组,包含路由的各种配置选项,例如请求方法、处理函数、参数验证等等。
  • $override: 是否覆盖已存在的路由。

4.1 $args 详解

$args 数组是路由配置的核心。它包含以下几个重要的键:

  • methods: 允许的 HTTP 请求方法。可以是 GET, POST, PUT, DELETE, PATCH,或者 WP_REST_Server::READABLE, WP_REST_Server::EDITABLE, WP_REST_Server::DELETABLE 等常量。
  • callback: 处理函数。当请求匹配该路由时,该函数会被调用。
  • permission_callback: 权限验证函数。该函数用于验证当前用户是否有权限访问该路由。
  • args: 一个数组,定义了请求参数的格式和验证规则。

4.2 路由注册示例

add_action( 'rest_api_init', function () {
  register_rest_route( 'myplugin/v1', '/books', array(
    'methods'  => 'GET',
    'callback' => 'my_plugin_get_books',
    'permission_callback' => '__return_true', // 允许所有人访问
  ) );

  register_rest_route( 'myplugin/v1', '/books/(?P<id>d+)', array(
    'methods'  => 'GET',
    'callback' => 'my_plugin_get_book',
    'permission_callback' => '__return_true',
    'args' => array(
      'id' => array(
        'validate_callback' => 'rest_validate_request_arg',
        'sanitize_callback' => 'absint',
        'required' => true,
      ),
    ),
  ) );
} );

function my_plugin_get_books( $request ) {
  // 从数据库中获取所有书籍
  $books = get_posts( array( 'post_type' => 'book', 'numberposts' => -1 ) );
  $data = array();
  foreach ( $books as $book ) {
    $data[] = array(
      'id' => $book->ID,
      'title' => $book->post_title,
      'content' => $book->post_content,
    );
  }
  return $data;
}

function my_plugin_get_book( $request ) {
  $id = $request['id'];
  $book = get_post( $id );
  if ( empty( $book ) ) {
    return new WP_Error( 'book_not_found', 'Book not found', array( 'status' => 404 ) );
  }
  $data = array(
    'id' => $book->ID,
    'title' => $book->post_title,
    'content' => $book->post_content,
  );
  return $data;
}

在这个例子中,我们注册了两个路由:

  • /myplugin/v1/books: 用于获取所有书籍。
  • /myplugin/v1/books/{id}: 用于获取指定 ID 的书籍。

注意 (?P<id>d+) 是一个正则表达式,用于匹配 URL 中的 ID。(?P<name>pattern) 这种写法允许你命名正则表达式中的捕获组,方便在处理函数中通过 $request['id'] 获取 ID 值。

5. 权限验证:谁能吃,谁不能吃

权限验证是 REST API 安全的重要组成部分。permission_callback 函数用于验证当前用户是否有权限访问该路由。

5.1 默认权限验证

如果没有指定 permission_callback,默认情况下,REST API 会使用 rest_authentication() 函数进行验证。rest_authentication() 函数会检查当前用户是否已经登录。

5.2 自定义权限验证

你可以自定义 permission_callback 函数,以实现更复杂的权限验证逻辑。例如,你可以检查当前用户是否具有特定的角色或权限。

function my_plugin_check_permission( $request ) {
  if ( ! current_user_can( 'edit_posts' ) ) {
    return new WP_Error( 'rest_forbidden', 'You do not have permission to access this resource.', array( 'status' => 401 ) );
  }
  return true;
}

register_rest_route( 'myplugin/v1', '/books', array(
  'methods'  => 'POST',
  'callback' => 'my_plugin_create_book',
  'permission_callback' => 'my_plugin_check_permission',
) );

在这个例子中,我们定义了一个 my_plugin_check_permission() 函数,它会检查当前用户是否具有 edit_posts 权限。如果没有,则返回一个错误。

6. 参数验证和处理:确保食材新鲜

参数验证和处理是 REST API 的另一个重要组成部分。它可以确保客户端传递的参数符合预期格式,并防止恶意攻击。

6.1 参数定义

$args 数组中,可以使用 args 键来定义请求参数的格式和验证规则。

register_rest_route( 'myplugin/v1', '/books', array(
  'methods'  => 'POST',
  'callback' => 'my_plugin_create_book',
  'permission_callback' => 'my_plugin_check_permission',
  'args' => array(
    'title' => array(
      'validate_callback' => 'rest_validate_request_arg',
      'sanitize_callback' => 'sanitize_text_field',
      'required' => true,
    ),
    'content' => array(
      'validate_callback' => 'rest_validate_request_arg',
      'sanitize_callback' => 'wp_kses_post',
    ),
  ),
) );

在这个例子中,我们定义了两个参数:titlecontent

  • validate_callback: 验证函数。该函数用于验证参数的值是否符合预期格式。
  • sanitize_callback: 清理函数。该函数用于清理参数的值,以防止恶意攻击。
  • required: 是否必须。如果设置为 true,则客户端必须传递该参数。

6.2 常用验证和清理函数

WordPress 提供了一些常用的验证和清理函数,可以直接使用。

  • rest_validate_request_arg(): 默认的验证函数。它会检查参数的值是否为空。
  • sanitize_text_field(): 用于清理文本字段。
  • wp_kses_post(): 用于清理 HTML 内容。
  • absint(): 用于将字符串转换为整数。
  • is_email(): 用于验证是否为有效的电子邮件地址。

6.3 自定义验证和清理函数

你也可以自定义验证和清理函数,以实现更复杂的逻辑。

function my_plugin_validate_title( $value, $request, $param ) {
  if ( strlen( $value ) > 100 ) {
    return new WP_Error( 'title_too_long', 'Title is too long', array( 'status' => 400 ) );
  }
  return true;
}

register_rest_route( 'myplugin/v1', '/books', array(
  'methods'  => 'POST',
  'callback' => 'my_plugin_create_book',
  'permission_callback' => 'my_plugin_check_permission',
  'args' => array(
    'title' => array(
      'validate_callback' => 'my_plugin_validate_title',
      'sanitize_callback' => 'sanitize_text_field',
      'required' => true,
    ),
  ),
) );

在这个例子中,我们定义了一个 my_plugin_validate_title() 函数,它会检查标题的长度是否超过 100 个字符。

7. WP_REST_RequestWP_REST_Response:请求和响应的容器

WP_REST_RequestWP_REST_Response 类分别用于封装 HTTP 请求和响应的信息。

7.1 WP_REST_Request

WP_REST_Request 类包含以下重要方法:

  • get_method(): 获取请求方法 (GET, POST, etc.)。
  • get_route(): 获取请求的路由。
  • get_params(): 获取所有请求参数。
  • get_param( $name ): 获取指定名称的请求参数。
  • get_header( $name ): 获取指定名称的请求头。

7.2 WP_REST_Response

WP_REST_Response 类包含以下重要方法:

  • set_data( $data ): 设置响应数据。
  • get_data(): 获取响应数据。
  • set_status( $status ): 设置 HTTP 状态码。
  • get_status(): 获取 HTTP 状态码。
  • header( $key, $value ): 设置响应头。

8. 错误处理:犯错不可怕,重要的是知道错在哪儿

REST API 的错误处理非常重要。当发生错误时,REST API 应该返回一个包含错误信息的 JSON 响应。

8.1 WP_Error

WordPress 提供了一个 WP_Error 类,用于封装错误信息。

$error = new WP_Error( 'book_not_found', 'Book not found', array( 'status' => 404 ) );
return $error;

WP_Error 类的构造函数接受三个参数:

  • $code: 错误代码。
  • $message: 错误信息。
  • $data: 附加数据,例如 HTTP 状态码。

8.2 错误响应格式

REST API 会将 WP_Error 对象转换为 JSON 格式的错误响应。

{
  "code": "book_not_found",
  "message": "Book not found",
  "data": {
    "status": 404
  }
}

9. 总结:REST API 的乐高积木

WP_REST_Server 类就像一个乐高底板,你可以通过注册路由,定义参数,设置权限,来构建各种各样的 REST API。 理解它的工作原理,可以帮助你更好地开发 WordPress REST API,并构建更强大的应用程序。

组件 职责
WP_REST_Server 接收请求,路由匹配,调用处理函数,发送响应。
register_rest_route() 注册路由,定义 URL 和处理函数之间的关系。
WP_REST_Request 封装 HTTP 请求的信息,包括请求方法、URL、请求头、请求参数等等。
WP_REST_Response 封装 HTTP 响应的信息,包括响应数据、HTTP 状态码、响应头等等。
permission_callback 权限验证函数,用于验证当前用户是否有权限访问该路由。
validate_callbacksanitize_callback 参数验证和清理函数,用于确保客户端传递的参数符合预期格式,并防止恶意攻击。
WP_Error 封装错误信息,用于在发生错误时返回包含错误信息的 JSON 响应。

希望今天的讲座对你有所帮助! 感谢各位的参与!

发表回复

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