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
,以获取所有文章。
-
接收请求: WordPress 接收到 HTTP 请求,并确定这是一个 REST API 请求。通常,REST API 请求的 URL 会以
/wp-json/
开头。 -
创建
WP_REST_Request
对象:WP_REST_Server
创建一个WP_REST_Request
对象,用于封装请求的所有信息,包括请求方法 (GET, POST, etc.)、URL、请求头、请求参数等等。$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
-
路由匹配:
WP_REST_Server
遍历$routes
数组,尝试找到与当前请求 URL 和请求方法匹配的路由。这就像警察拿着通缉令在人群中寻找罪犯一样。 -
调用处理函数: 如果找到匹配的路由,
WP_REST_Server
会调用该路由对应的处理函数。处理函数负责执行实际的业务逻辑,比如从数据库中获取文章数据。 -
创建
WP_REST_Response
对象: 处理函数返回数据后,WP_REST_Server
创建一个WP_REST_Response
对象,用于封装响应的所有信息,包括响应数据、HTTP 状态码、响应头等等。$response = new WP_REST_Response( $data, 200 ); // $data 是文章数据,200 是 HTTP 状态码
-
发送响应:
WP_REST_Server
将WP_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',
),
),
) );
在这个例子中,我们定义了两个参数:title
和 content
。
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_Request
和 WP_REST_Response
:请求和响应的容器
WP_REST_Request
和 WP_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_callback 和 sanitize_callback |
参数验证和清理函数,用于确保客户端传递的参数符合预期格式,并防止恶意攻击。 |
WP_Error |
封装错误信息,用于在发生错误时返回包含错误信息的 JSON 响应。 |
希望今天的讲座对你有所帮助! 感谢各位的参与!