好的,我们开始吧。
今天我们来深入探讨 WordPress REST API 请求的生命周期,从注册路由 register_rest_route
开始,一直到最终的响应输出。 这其中涉及的组件繁多,流程复杂,理解这个过程对开发高质量的 REST API 接口至关重要。
一、register_rest_route
: 路由注册的起点
在 WordPress 中,要使一个自定义的函数能够通过 REST API 访问,首先需要注册一个路由。这个注册的过程由 register_rest_route
函数完成。
register_rest_route(
string $namespace,
string $route,
array $args = array(),
bool $override = false
);
$namespace
: API 的命名空间,通常是你的插件或主题的名字。 避免与其他插件冲突。 例如:my-plugin/v1
。$route
: API 的路由,定义了访问该 API 的 URL 结构。 例如:/books
或/books/(?P<id>d+)
。 后者使用了正则表达式,(?P<id>d+)
表示一个名为id
的参数,其值为一个或多个数字。$args
: 一个数组,包含了路由的处理方法和其他配置信息。 这是最关键的部分,我们稍后会详细讲解。$override
: 一个布尔值,默认为false
。 如果设置为true
,则允许覆盖已存在的同名路由(不建议这样做,除非你明确知道自己在做什么)。
$args
数组的结构
$args
数组是配置路由行为的核心。 它通常包含以下几个关键的键:
methods
: 指定允许的 HTTP 方法。 可以是GET
,POST
,PUT
,DELETE
,PATCH
中的一个或多个。 使用WP_REST_Server::READABLE
(等同于GET
),WP_REST_Server::EDITABLE
(等同于POST, PUT, PATCH
),WP_REST_Server::DELETABLE
(等同于DELETE
) 可以提高代码可读性。callback
: 指定处理该路由请求的回调函数。 这个函数负责接收请求数据,执行相应的逻辑,并返回响应数据。permission_callback
: 指定一个回调函数,用于检查当前用户是否有权限访问该路由。 如果返回true
,则允许访问;否则,拒绝访问。args
: 一个数组,用于定义路由参数的验证和清理规则。
示例
add_action( 'rest_api_init', function () {
register_rest_route( 'my-plugin/v1', '/books', array(
'methods' => 'GET',
'callback' => 'my_plugin_get_books',
'permission_callback' => '__return_true', // 允许所有用户访问
) );
register_rest_route( 'my-plugin/v1', '/books/(?P<id>d+)', array(
'methods' => 'GET',
'callback' => 'my_plugin_get_book',
'permission_callback' => 'my_plugin_check_permission',
'args' => array(
'id' => array(
'validate_callback' => 'is_numeric',
'sanitize_callback' => 'absint',
'required' => true,
'description' => 'Book ID.'
),
),
) );
} );
function my_plugin_get_books( WP_REST_Request $request ) {
// 从数据库获取所有书籍
$books = get_posts( array( 'post_type' => 'book', 'posts_per_page' => -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( WP_REST_Request $request ) {
$id = $request['id'];
$book = get_post( $id );
if ( empty( $book ) ) {
return new WP_Error( 'book_not_found', 'Book not found.', array( 'status' => 404 ) );
}
return array(
'id' => $book->ID,
'title' => $book->post_title,
'content' => $book->post_content,
);
}
function my_plugin_check_permission(WP_REST_Request $request){
// 检查用户是否具有 'edit_posts' 权限
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;
}
二、请求接收与路由匹配
当一个 REST API 请求到达 WordPress 时,它会经过以下几个关键步骤:
- URL 解析: WordPress 会解析请求的 URL,提取出命名空间和路由信息。
- 路由匹配: WordPress REST API 核心会遍历已注册的路由,尝试找到与请求 URL 匹配的路由。
- 参数提取: 如果找到匹配的路由,WordPress 会根据路由定义,从 URL 和请求体中提取参数。
- 权限检查: 在执行回调函数之前,WordPress 会调用
permission_callback
函数,检查当前用户是否有权限访问该路由。 - 回调函数执行: 如果权限检查通过,WordPress 会调用该路由的
callback
函数,并将请求参数传递给该函数。
WP_REST_Request
对象
回调函数接收一个 WP_REST_Request
对象作为参数。 这个对象包含了所有关于请求的信息,包括:
get_method()
: 返回请求的 HTTP 方法 (例如:’GET’, ‘POST’, ‘PUT’, ‘DELETE’)。get_params()
: 返回所有请求参数的数组。get_param( $param )
: 返回指定名称的请求参数。get_headers()
: 返回所有请求头的数组。get_header( $header )
: 返回指定名称的请求头。get_body()
: 返回请求体的内容。get_file_params()
: 返回上传的文件参数。has_valid_params()
: 检查请求参数是否有效(基于路由注册时定义的args
)。
三、参数验证与清理
在回调函数执行之前,REST API 框架会根据 register_rest_route
中 args
定义的规则,对请求参数进行验证和清理。
validate_callback
: 用于验证参数是否符合预期。 如果验证失败,则返回false
或一个WP_Error
对象。sanitize_callback
: 用于清理参数,使其符合预期格式。 例如,可以使用absint
将参数转换为正整数。required
: 布尔值,指定参数是否是必须的。 如果设置为true
,但请求中缺少该参数,则验证会失败。default
: 如果请求中缺少该参数,则使用该默认值。type
: 指定参数的类型,例如:string
,integer
,boolean
,array
,object
. 虽然 WordPress 没有强制类型检查,但可以用于生成 API 文档。description
: 参数的描述信息,用于生成 API 文档。
示例
register_rest_route( 'my-plugin/v1', '/items', array(
'methods' => 'POST',
'callback' => 'my_plugin_create_item',
'args' => array(
'title' => array(
'validate_callback' => 'is_string',
'sanitize_callback' => 'sanitize_text_field',
'required' => true,
'description' => 'Item title.'
),
'content' => array(
'validate_callback' => 'is_string',
'sanitize_callback' => 'wp_kses_post',
'description' => 'Item content.'
),
'status' => array(
'default' => 'draft',
'validate_callback' => function( $param, $request, $key ) {
return in_array( $param, array( 'draft', 'pending', 'publish' ) );
},
'sanitize_callback' => 'sanitize_text_field',
'description' => 'Item status.'
),
),
) );
function my_plugin_create_item( WP_REST_Request $request ) {
$title = $request['title'];
$content = $request['content'];
$status = $request['status'];
$post_id = wp_insert_post( array(
'post_title' => $title,
'post_content' => $content,
'post_status' => $status,
) );
if ( is_wp_error( $post_id ) ) {
return $post_id;
}
return rest_ensure_response( array( 'id' => $post_id ) );
}
在这个例子中:
title
是必须的,必须是字符串,并且会被sanitize_text_field
函数清理。content
必须是字符串,并且会被wp_kses_post
函数清理 (用于过滤 HTML 标签)。status
默认为draft
,必须是draft
,pending
,publish
中的一个,并且会被sanitize_text_field
函数清理。
四、响应生成与输出
回调函数负责生成响应数据。 响应数据可以是任何 PHP 数据类型,例如:数组,对象,字符串,数字等。
WP_REST_Response
对象
为了提供更大的灵活性和控制力,建议使用 WP_REST_Response
对象来封装响应数据。
$response = new WP_REST_Response( $data, $status, $headers );
$data
: 响应数据。$status
: HTTP 状态码 (例如:200, 201, 400, 404, 500)。$headers
: 响应头。
常用方法
set_data( $data )
: 设置响应数据。get_data()
: 获取响应数据。set_status( $status )
: 设置 HTTP 状态码。get_status()
: 获取 HTTP 状态码。header( $key, $value )
: 设置响应头。get_headers()
: 获取所有响应头。link_header( $rel, $link )
: 设置链接头 (用于 HATEOAS)。
rest_ensure_response()
函数
为了方便起见,可以使用 rest_ensure_response()
函数来确保响应数据被封装成 WP_REST_Response
对象。
$response = rest_ensure_response( $data );
如果 $data
已经是 WP_REST_Response
对象,则直接返回 $data
。 否则,将 $data
封装成一个新的 WP_REST_Response
对象,状态码默认为 200。
错误处理
在 REST API 中,错误处理非常重要。 应该使用 WP_Error
对象来表示错误。
return new WP_Error( $code, $message, $data );
$code
: 错误代码 (字符串)。$message
: 错误消息 (字符串)。$data
: 附加数据 (数组)。 通常包含status
键,用于指定 HTTP 状态码。
示例
function my_plugin_get_book( WP_REST_Request $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 rest_ensure_response( $data );
}
响应输出
当回调函数返回 WP_REST_Response
对象或 WP_Error
对象时,REST API 核心会自动将其转换为 JSON 格式并输出到客户端。 WordPress 会根据 Content-Type
请求头来决定输出的格式。 默认情况下,使用 JSON 格式。
五、中间件与扩展
WordPress REST API 提供了一些钩子,允许开发者在请求处理的不同阶段插入自定义逻辑。 这些钩子可以用于实现各种功能,例如:
- 身份验证: 自定义身份验证方法。
- 数据转换: 在数据返回给客户端之前,对其进行转换。
- 日志记录: 记录 API 请求和响应。
- 缓存: 缓存 API 响应,提高性能。
常用的钩子
rest_authentication_errors
: 用于处理身份验证错误。rest_pre_dispatch
: 在路由回调函数执行之前执行。rest_post_dispatch
: 在路由回调函数执行之后执行。rest_prepare_{$post_type}
: 用于修改特定文章类型的 REST API 响应数据。
示例
add_filter( 'rest_prepare_post', 'my_plugin_add_custom_field', 10, 3 );
function my_plugin_add_custom_field( $data, $post, $request ) {
$data->data['custom_field'] = get_post_meta( $post->ID, 'my_custom_field', true );
return $data;
}
这个例子展示了如何使用 rest_prepare_post
钩子,在文章的 REST API 响应中添加一个名为 custom_field
的自定义字段。
六、示例表格:关键函数与对象
函数/对象 | 描述 | 示例 |
---|---|---|
register_rest_route |
注册一个 REST API 路由。 | register_rest_route( 'my-plugin/v1', '/books', array( 'methods' => 'GET', 'callback' => 'my_plugin_get_books' ) ); |
WP_REST_Request |
代表一个 REST API 请求。 包含了请求的所有信息,例如:HTTP 方法,参数,头部等。 | $request->get_param( 'id' ) 获取名为 ‘id’ 的参数。 $request->get_method() 获取 HTTP 方法。 |
WP_REST_Response |
代表一个 REST API 响应。 包含了响应数据,HTTP 状态码,头部等。 | $response = new WP_REST_Response( $data, 200 ); 创建一个 HTTP 状态码为 200 的响应。 $response->set_data( $data ) 设置响应数据。 |
WP_Error |
代表一个错误。 用于在 REST API 中返回错误信息。 | return new WP_Error( 'book_not_found', 'Book not found.', array( 'status' => 404 ) ); 创建一个 HTTP 状态码为 404 的错误响应。 |
rest_ensure_response |
确保数据被封装成 WP_REST_Response 对象。 如果数据已经是 WP_REST_Response 对象,则直接返回;否则,将其封装成一个新的 WP_REST_Response 对象。 |
return rest_ensure_response( $data ); |
is_numeric |
PHP 内置函数,检查变量是否为数字或数字字符串。 通常用作 validate_callback 。 |
'id' => array( 'validate_callback' => 'is_numeric' ) |
absint |
PHP 内置函数,将变量转换为正整数。 通常用作 sanitize_callback 。 |
'id' => array( 'sanitize_callback' => 'absint' ) |
sanitize_text_field |
WordPress 函数,清理文本字段,移除 HTML 标签和编码特殊字符。 通常用作 sanitize_callback 。 |
'title' => array( 'sanitize_callback' => 'sanitize_text_field' ) |
wp_kses_post |
WordPress 函数,过滤 HTML 标签,只允许安全的标签和属性。 通常用作 sanitize_callback ,用于处理文章内容。 |
'content' => array( 'sanitize_callback' => 'wp_kses_post' ) |
current_user_can |
WordPress 函数,检查当前用户是否具有指定的权限。 通常用在 permission_callback 中。 |
function my_plugin_check_permission(WP_REST_Request $request){ if ( ! current_user_can( 'edit_posts' ) ) { return new WP_Error( 'rest_forbidden', 'You do not have permission.', array( 'status' => 401 ) ); } return true; } |
七、总结:掌握REST API生命周期
至此,我们已经详细地分析了 WordPress REST API 请求的生命周期,从路由注册到响应输出的整个过程。 记住关键的步骤,例如注册路由、验证参数、生成响应以及处理错误,并灵活运用 WordPress 提供的钩子来扩展 API 的功能。 掌握这些知识能够帮助你开发出更健壮、安全和高效的 REST API 接口。