各位观众,晚上好!我是今晚的导游,将带大家深入探险 WordPress REST API 的核心——WP_REST_Server
类。准备好了吗?系好安全带,我们要出发了!
第一站:WP_REST_Server
是个啥?
简单来说,WP_REST_Server
就是 WordPress REST API 的大脑和神经中枢。它负责接收 HTTP 请求,解析请求信息,找到对应的处理函数(也就是路由),然后执行函数并返回结果。 你可以把它想象成一个超级厉害的总机接线员,负责把各种电话(HTTP 请求)转接到正确的人(处理函数)那里。
第二站:请求接收与解析
WP_REST_Server
的生命之旅始于 serve_request()
方法。这个方法是整个 REST API 的入口点,它会接收到 WordPress 丢过来的 HTTP 请求。
public function serve_request( $path = null ) {
// 初始化请求方法
$this->method = $this->get_method();
// 设置请求路径
if ( null === $path ) {
$path = $this->get_rest_url();
}
// 解析请求
$result = $this->dispatch( $this->parse_request( $path ) );
// 发送响应
$this->send_response( $result );
}
$this->get_method()
:这个方法用来获取 HTTP 请求的方法 (GET, POST, PUT, DELETE 等等)。$this->get_rest_url()
:获取 REST API 的根 URL。$this->parse_request()
:这个方法是关键,它负责解析请求,提取出请求的路径、参数等信息,并将这些信息封装成一个WP_REST_Request
对象。$this->dispatch()
:根据解析后的请求,找到对应的处理函数并执行。$this->send_response()
:将处理函数返回的结果格式化并发送给客户端。
重点剖析:parse_request()
parse_request()
方法的作用是将 URL 分解成易于理解的片段。
public function parse_request( $path ) {
$request = new WP_REST_Request( $this->method );
// 从 URL 中提取路径参数
$path = trim( $path, '/' );
$path = explode( '/', $path );
$route = array_shift( $path );
// 从查询字符串中提取参数
$params = $_GET;
// 将路径参数和查询字符串参数合并到请求对象中
$request->set_route( $route );
$request->set_url_params( $path );
$request->set_query_params( $params );
// 处理请求体
$body = $this->get_raw_data();
if ( $body ) {
$request->set_body( $body );
}
// 处理上传文件
$files = $_FILES;
if ( $files ) {
$request->set_file_params( $files );
}
//... 其他处理逻辑,例如处理请求头等
return $request;
}
简单来说,这个方法做了以下事情:
- 创建一个
WP_REST_Request
对象,用于存储请求的所有信息。 - 从 URL 中提取路由(route),也就是 API 的端点。例如,如果 URL 是
/wp-json/my-plugin/v1/items/123
,那么路由就是my-plugin/v1/items
。 - 从 URL 中提取路径参数(url params)。 例如,在上面的例子中,
123
可能会被解析成id
为123
的参数。 - 从查询字符串(query string)中提取参数。例如,如果 URL 是
/wp-json/my-plugin/v1/items?status=published&per_page=10
,那么就会提取出status
和per_page
两个参数。 - 处理请求体(body),也就是 POST 或 PUT 请求中发送的数据。
- 处理上传的文件。
最终,parse_request()
方法会返回一个包含了所有请求信息的 WP_REST_Request
对象。
第三站:路由注册与匹配
路由(route)是 REST API 的核心概念之一。它定义了 API 的端点以及处理该端点的函数。WP_REST_Server
使用 $this->endpoints
数组来存储所有已注册的路由。
注册路由:register_route()
要注册一个路由,你需要使用 register_route()
方法。
public function register_route( $namespace, $route, $args = array(), $override = false ) {
// 格式化路由参数
$route = $this->normalize_route( $route );
if ( ! isset( $this->endpoints[ $namespace ] ) ) {
$this->endpoints[ $namespace ] = array();
}
if ( isset( $this->endpoints[ $namespace ][ $route ] ) && ! $override ) {
// 路由已存在,且不允许覆盖
return false;
}
// 将路由信息存储到 $this->endpoints 数组中
$this->endpoints[ $namespace ][ $route ] = $args;
return true;
}
$namespace
:API 的命名空间。例如,my-plugin/v1
。$route
:API 的端点。例如,items
或items/(?P<id>d+)
。$args
:一个数组,包含路由的处理函数、请求方法、权限验证回调函数等信息。$override
:一个布尔值,表示是否允许覆盖已存在的路由。
$args
数组的结构
$args
数组是路由注册时最重要的参数,它定义了如何处理该路由的请求。
$args = array(
'methods' => 'GET', // 或者 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'
'callback' => 'my_plugin_get_items', // 处理请求的回调函数
'permission_callback' => 'my_plugin_check_permission', // 权限验证回调函数
'args' => array( // 参数验证规则
'id' => array(
'validate_callback' => 'is_numeric',
'sanitize_callback' => 'absint',
'required' => true,
),
),
);
methods
:允许的 HTTP 请求方法。可以是单个方法,也可以是方法数组。callback
:处理请求的回调函数。这个函数接收一个WP_REST_Request
对象作为参数,并返回一个WP_REST_Response
对象或一个WP_Error
对象。permission_callback
:权限验证回调函数。这个函数接收一个WP_REST_Request
对象作为参数,并返回一个布尔值,表示当前用户是否有权限访问该路由。args
:一个数组,定义了请求参数的验证和清理规则。
匹配路由:match_request()
当 WP_REST_Server
接收到一个请求后,它会使用 match_request()
方法来找到对应的路由。
protected function match_request( $request ) {
$route = $request->get_route();
$namespace = $request->get_namespace();
if ( ! isset( $this->endpoints[ $namespace ] ) ) {
return null; // 命名空间不存在
}
$routes = $this->endpoints[ $namespace ];
foreach ( $routes as $route_regex => $route_args ) {
if ( preg_match( '@^' . $route_regex . '$@i', $route, $matches ) ) {
// 路由匹配成功
return array(
'regex' => $route_regex,
'args' => $route_args,
'matches' => $matches,
);
}
}
return null; // 没有找到匹配的路由
}
这个方法会遍历 $this->endpoints
数组,使用正则表达式来匹配请求的路由。如果找到匹配的路由,它会返回一个包含路由信息和匹配结果的数组。
第四站:请求分发与执行
找到匹配的路由后,WP_REST_Server
会使用 dispatch()
方法来执行处理函数。
public function dispatch( WP_REST_Request $request ) {
try {
$result = $this->handle_request( $request );
// 将结果转换为 WP_REST_Response 对象
if ( ! ( $result instanceof WP_REST_Response ) && ! ( $result instanceof WP_Error ) ) {
$result = rest_ensure_response( $result );
}
return $result;
} catch ( Exception $e ) {
$error = new WP_Error(
'rest_exception',
$e->getMessage(),
array( 'status' => 500 )
);
return $error;
}
}
$this->handle_request()
:这个方法负责执行具体的处理函数。rest_ensure_response()
:确保返回的结果是一个WP_REST_Response
对象或一个WP_Error
对象。try...catch
块:用于捕获处理函数抛出的异常,并将其转换为一个WP_Error
对象。
重点剖析:handle_request()
handle_request()
方法是请求分发的核心。
protected function handle_request( WP_REST_Request $request ) {
$matched_route = $this->match_request( $request );
if ( ! $matched_route ) {
return new WP_Error(
'rest_no_route',
__( 'No route was found matching the URL and request method' ),
array( 'status' => 404 )
);
}
$route_args = $matched_route['args'];
$matches = $matched_route['matches'];
// 验证权限
if ( isset( $route_args['permission_callback'] ) ) {
$permission = call_user_func( $route_args['permission_callback'], $request );
if ( is_wp_error( $permission ) ) {
return $permission;
}
if ( ! $permission ) {
return new WP_Error(
'rest_forbidden',
__( 'Sorry, you are not allowed to do that.' ),
array( 'status' => rest_authorization_required_code() )
);
}
}
// 验证参数
$params = $request->get_params();
$validated_params = $this->validate_request_arg_params( $params, $route_args, $request );
if ( is_wp_error( $validated_params ) ) {
return $validated_params;
}
$request->set_attributes( array( 'args' => $validated_params ) );
// 执行回调函数
if ( isset( $route_args['callback'] ) ) {
$response = call_user_func( $route_args['callback'], $request );
return $response;
}
return new WP_Error(
'rest_no_callback',
__( 'Route matched, but no callback was specified.' ),
array( 'status' => 500 )
);
}
这个方法做了以下事情:
- 找到匹配的路由。
- 验证权限。如果路由定义了
permission_callback
,则会调用该函数来检查当前用户是否有权限访问该路由。 - 验证参数。如果路由定义了
args
,则会根据args
中定义的规则来验证请求参数。 - 执行回调函数。如果路由定义了
callback
,则会调用该函数来处理请求。
参数验证:validate_request_arg_params()
validate_request_arg_params()
方法用于验证请求参数是否符合路由定义中 args
的规则。
protected function validate_request_arg_params( $params, $route_args, $request ) {
$validated_params = array();
if ( ! isset( $route_args['args'] ) ) {
return $params; // 没有定义参数验证规则
}
$arg_defs = $route_args['args'];
foreach ( $arg_defs as $arg_name => $arg_def ) {
if ( ! isset( $params[ $arg_name ] ) ) {
if ( isset( $arg_def['required'] ) && $arg_def['required'] ) {
return new WP_Error(
'rest_missing_callback_param',
sprintf( __( 'Missing parameter %s' ), $arg_name ),
array( 'status' => 400, 'params' => array( $arg_name ) )
);
}
continue; // 参数不存在,且不是必需的
}
$param_value = $params[ $arg_name ];
// 验证参数
if ( isset( $arg_def['validate_callback'] ) ) {
$is_valid = call_user_func( $arg_def['validate_callback'], $param_value, $request, $arg_name );
if ( is_wp_error( $is_valid ) ) {
return $is_valid;
}
if ( ! $is_valid ) {
return new WP_Error(
'rest_invalid_param',
sprintf( __( 'Invalid parameter %s' ), $arg_name ),
array( 'status' => 400, 'params' => array( $arg_name ) )
);
}
}
// 清理参数
if ( isset( $arg_def['sanitize_callback'] ) ) {
$param_value = call_user_func( $arg_def['sanitize_callback'], $param_value, $request, $arg_name );
}
$validated_params[ $arg_name ] = $param_value;
}
return $validated_params;
}
这个方法会遍历路由定义中 args
的每一个参数,并执行以下操作:
- 检查参数是否存在。如果参数是必需的,但请求中没有提供该参数,则会返回一个
WP_Error
对象。 - 验证参数。如果参数定义了
validate_callback
,则会调用该函数来验证参数的值。 - 清理参数。如果参数定义了
sanitize_callback
,则会调用该函数来清理参数的值。
第五站:响应发送
dispatch()
方法执行完处理函数后,会将返回的结果传递给 send_response()
方法。
public function send_response( $response, $status = null, $headers = array() ) {
// 处理 WP_Error 对象
if ( is_wp_error( $response ) ) {
$data = $response->get_error_data();
if ( is_array( $data ) && isset( $data['status'] ) ) {
$status = (int) $data['status'];
} else {
$status = 500;
}
$response = array(
'code' => $response->get_error_code(),
'message' => $response->get_error_message(),
'data' => $data,
);
}
// 确保响应是一个数组或对象
if ( ! is_array( $response ) && ! is_object( $response ) ) {
$response = array( 'message' => (string) $response );
}
// 设置 Content-Type 头部
if ( ! headers_sent() ) {
header( 'Content-Type: application/json; charset=' . get_option( 'blog_charset' ) );
}
// 设置状态码
if ( null !== $status ) {
status_header( $status );
}
// 设置其他头部
foreach ( $headers as $key => $value ) {
header( "$key: $value" );
}
// 将响应转换为 JSON 格式并输出
echo wp_json_encode( $response );
// 退出
exit;
}
这个方法做了以下事情:
- 处理
WP_Error
对象。如果响应是一个WP_Error
对象,则会提取错误信息,并设置 HTTP 状态码。 - 确保响应是一个数组或对象。
- 设置
Content-Type
头部为application/json
。 - 设置 HTTP 状态码。
- 设置其他头部。
- 将响应转换为 JSON 格式并输出。
- 退出。
总结
WP_REST_Server
类是 WordPress REST API 的核心,它负责接收、解析、路由和分发 HTTP 请求,并将处理结果以 JSON 格式返回给客户端。理解 WP_REST_Server
类的工作原理,可以帮助你更好地使用和扩展 WordPress REST API。
表格总结
步骤 | 方法 | 描述 |
---|---|---|
1. 接收请求 | serve_request() |
接收 HTTP 请求,设置请求方法和路径。 |
2. 解析请求 | parse_request() |
解析 URL 和请求体,提取路由、参数等信息,并封装成 WP_REST_Request 对象。 |
3. 路由注册 | register_route() |
注册 API 路由,定义端点、处理函数、权限验证等信息。 |
4. 路由匹配 | match_request() |
匹配请求的路由,找到对应的处理函数。 |
5. 请求分发 | dispatch() |
分发请求到对应的处理函数,执行权限验证、参数验证等操作。 |
6. 处理请求 | handle_request() |
执行具体的处理函数,并返回结果。 |
7. 参数验证 | validate_request_arg_params() |
验证请求参数是否符合路由定义中 args 的规则。 |
8. 发送响应 | send_response() |
将处理结果格式化为 JSON 格式,并发送给客户端。 |
希望这次旅行对大家有所帮助!下次再见!