WordPress REST API 响应对象详解:WP_REST_Response
类源码剖析
嘿,各位代码爱好者!今天咱们来聊聊 WordPress REST API 的核心部分:WP_REST_Response
类。这玩意儿,说白了,就是你构建 REST API 响应的容器,就像你用漂亮的盒子把礼物包装起来一样。没它,你的 API 就只能吐出一些冷冰冰的数据,缺少了应有的格式和信息。
咱们今天就深入 WP_REST_Response
的源码,看看它到底是怎么工作的,以及怎么用它来构建高质量的 REST API 响应。
1. 基础概念:REST API 响应的结构
在深入代码之前,咱们先明确一下 REST API 响应的基本结构。一个典型的 REST API 响应包含以下几个关键部分:
- 状态码 (Status Code): 指示请求是否成功,例如 200 (OK), 404 (Not Found), 500 (Internal Server Error) 等。
- 头部 (Headers): 包含关于响应的元数据,例如 Content-Type, Cache-Control 等。
- 正文 (Body): 实际返回的数据,通常是 JSON 格式。
WP_REST_Response
类就是用来封装这些信息的。
2. WP_REST_Response
类的诞生:构造函数
咱们先来看看 WP_REST_Response
类的构造函数:
/**
* Constructor.
*
* @param mixed $data Optional. Response data. Default null.
* @param int $status Optional. The HTTP status code. Default 200.
* @param array $headers Optional. Array of HTTP headers to set. Default empty array.
*/
public function __construct( $data = null, $status = 200, $headers = array() ) {
$this->set_data( $data );
$this->set_status( $status );
$this->set_headers( $headers );
}
很简单,对吧?构造函数接收三个参数:
$data
: 响应的数据,可以是任何类型,但通常是数组或对象,最终会被转换为 JSON。$status
: HTTP 状态码,默认为 200 (OK)。$headers
: HTTP 头部,是一个关联数组,键是头部名称,值是头部的值。
示例:
$response = new WP_REST_Response(
array(
'message' => 'Hello, world!',
'status' => 'success',
),
200,
array(
'Content-Type' => 'application/json',
'Cache-Control' => 'no-cache',
)
);
这段代码创建了一个 WP_REST_Response
对象,包含了数据、状态码和头部信息。
3. 设置和获取数据:set_data()
和 get_data()
WP_REST_Response
类提供了 set_data()
和 get_data()
方法来设置和获取响应的数据。
/**
* Sets the data for the response.
*
* @param mixed $data Data for the response.
*/
public function set_data( $data ) {
$this->data = $data;
}
/**
* Gets the data for the response.
*
* @return mixed Data for the response.
*/
public function get_data() {
return $this->data;
}
这两个方法非常直接,就是简单的设置和获取 $data
属性。
示例:
$response = new WP_REST_Response();
$response->set_data( array( 'message' => 'Updated data!' ) );
$data = $response->get_data();
echo $data['message']; // 输出: Updated data!
4. 设置和获取状态码:set_status()
和 get_status()
类似地,set_status()
和 get_status()
方法用于设置和获取 HTTP 状态码。
/**
* Sets the HTTP status code.
*
* @param int $status HTTP status code.
*/
public function set_status( $status ) {
$this->status = (int) $status;
}
/**
* Gets the HTTP status code.
*
* @return int HTTP status code.
*/
public function get_status() {
return $this->status;
}
示例:
$response = new WP_REST_Response();
$response->set_status( 404 );
$status = $response->get_status();
echo $status; // 输出: 404
5. 设置和获取头部:set_headers()
, get_headers()
, header()
HTTP 头部是响应的重要组成部分,WP_REST_Response
类提供了几个方法来处理它们:
set_headers( array $headers, bool $replace = true )
: 设置头部。get_headers()
: 获取所有头部。header( string $key, string $value, bool $replace = true )
: 设置单个头部。
/**
* Sets HTTP response headers.
*
* @param array $headers Array of HTTP headers to set.
* @param bool $replace Optional. Whether to replace the header, or add it. Default true.
*/
public function set_headers( $headers, $replace = true ) {
foreach ( (array) $headers as $key => $value ) {
$this->header( $key, $value, $replace );
}
}
/**
* Retrieves all HTTP response headers.
*
* @return array HTTP response headers.
*/
public function get_headers() {
return $this->headers;
}
/**
* Sets a single HTTP header.
*
* @param string $key HTTP header key.
* @param string $value HTTP header value.
* @param bool $replace Optional. Whether to replace the header, or add it. Default true.
*/
public function header( $key, $value, $replace = true ) {
$key = $this->normalize_header_key( $key );
$value = (string) $value;
if ( $replace || ! isset( $this->headers[ $key ] ) ) {
$this->headers[ $key ] = $value;
} else {
$this->headers[ $key ] .= ', ' . $value;
}
}
/**
* Normalizes a header key to be properly case-insensitive.
*
* @param string $key Header key to normalize.
* @return string Normalized header key.
*/
protected function normalize_header_key( $key ) {
$key = strtolower( $key );
$key = str_replace( '_', '-', $key );
return $key;
}
注意: normalize_header_key()
方法会将头部名称转换为小写,并将下划线替换为短横线,以确保头部名称的一致性。
示例:
$response = new WP_REST_Response();
$response->header( 'Content-Type', 'application/json' );
$response->header( 'X-Custom-Header', 'My Value' );
$headers = $response->get_headers();
print_r( $headers );
// 输出:
// Array
// (
// [content-type] => application/json
// [x-custom-header] => My Value
// )
6. 添加链接关系:add_link()
和 remove_link()
REST API 提倡使用超媒体作为应用状态引擎 (HATEOAS)。这意味着响应应该包含指向相关资源的链接。WP_REST_Response
类提供了 add_link()
和 remove_link()
方法来添加和删除链接关系。
/**
* Adds a link relation.
*
* @param string $rel Relation type.
* @param string $href URL.
* @param array $attributes Optional. Attributes for the link. Default empty array.
*/
public function add_link( $rel, $href, $attributes = array() ) {
if ( empty( $this->links[ $rel ] ) ) {
$this->links[ $rel ] = array();
}
$this->links[ $rel ][] = array(
'href' => $href,
'attributes' => $attributes,
);
}
/**
* Removes a link relation.
*
* @param string $rel Relation type.
* @param string $href URL to remove.
*/
public function remove_link( $rel, $href ) {
if ( empty( $this->links[ $rel ] ) ) {
return;
}
foreach ( $this->links[ $rel ] as $key => $link ) {
if ( $link['href'] === $href ) {
unset( $this->links[ $rel ][ $key ] );
}
}
if ( empty( $this->links[ $rel ] ) ) {
unset( $this->links[ $rel ] );
}
}
示例:
$response = new WP_REST_Response();
$response->add_link( 'self', 'https://example.com/posts/1' );
$response->add_link( 'author', 'https://example.com/users/1', array( 'title' => 'John Doe' ) );
$links = $response->get_links();
print_r( $links );
// 输出:
// Array
// (
// [self] => Array
// (
// [0] => Array
// (
// [href] => https://example.com/posts/1
// [attributes] => Array
// (
// )
//
// )
//
// )
//
// [author] => Array
// (
// [0] => Array
// (
// [href] => https://example.com/users/1
// [attributes] => Array
// (
// [title] => John Doe
// )
//
// )
//
// )
//
// )
7. 获取链接关系:get_links()
get_links()
方法用于获取所有已添加的链接关系。
/**
* Retrieves all link relations.
*
* @return array Link relations.
*/
public function get_links() {
return $this->links;
}
8. 准备响应:prepare_response_for_collection()
这个方法用于将单个响应对象准备成集合响应的一部分。它主要用于分页或其他需要返回多个资源的场景。
/**
* Prepares the object for serialization into a collection.
*
* @return array Prepared data, which is likely to be an array
*/
public function prepare_response_for_collection() {
return $this->get_data();
}
通常,这个方法会返回 get_data()
的结果,但你可以根据需要进行自定义。
9. 转换为响应对象:to_array()
和 get_data_for_response()
这两个方法用于将 WP_REST_Response
对象转换为数组,以便进行序列化。to_array()
是一个公共方法,而 get_data_for_response()
是一个受保护的方法,用于获取用于响应的数据。
/**
* Returns the object as an array, suitable for returning in a response.
*
* @return array Data for response.
*/
public function to_array() {
$data = $this->get_data_for_response();
// If the data is already an array, just return it.
if ( is_array( $data ) ) {
return $data;
}
// Otherwise, wrap it in an array.
return array( 'data' => $data );
}
/**
* Get the data to be used in the response.
*
* @return mixed The data to be used in the response.
*/
protected function get_data_for_response() {
return $this->get_data();
}
to_array()
方法会检查数据是否已经是数组,如果是,则直接返回;否则,将其包装在一个包含 data
键的数组中。
10. 发送响应:与 WordPress 钩子的交互
WP_REST_Response
对象本身并不负责发送响应。它只是一个数据容器。WordPress REST API 使用钩子来处理响应的发送。例如,rest_pre_serve_request
钩子允许你修改响应对象,而 rest_send_cors_headers
钩子允许你设置 CORS 头部。
11. 实战演练:构建一个简单的 REST API 响应
现在,咱们来用 WP_REST_Response
类构建一个简单的 REST API 响应。假设我们要创建一个 API 端点,用于获取文章的信息。
add_action( 'rest_api_init', function () {
register_rest_route( 'my-plugin/v1', '/posts/(?P<id>d+)', array(
'methods' => 'GET',
'callback' => 'my_plugin_get_post',
) );
} );
function my_plugin_get_post( WP_REST_Request $request ) {
$post_id = $request['id'];
$post = get_post( $post_id );
if ( empty( $post ) ) {
return new WP_Error( 'rest_post_invalid_id', 'Invalid post ID.', array( 'status' => 404 ) );
}
$data = array(
'id' => $post->ID,
'title' => get_the_title( $post ),
'content' => apply_filters( 'the_content', $post->post_content ),
'link' => get_permalink( $post ),
);
$response = new WP_REST_Response( $data, 200 );
$response->header( 'Content-Type', 'application/json' );
$response->add_link( 'self', rest_url( 'my-plugin/v1/posts/' . $post->ID ) );
return $response;
}
这段代码做了以下几件事:
- 注册 REST API 路由: 使用
register_rest_route()
函数注册一个路由,用于获取文章的信息。 - 定义回调函数:
my_plugin_get_post()
函数是路由的回调函数,它接收一个WP_REST_Request
对象作为参数。 - 获取文章信息: 从请求中获取文章 ID,并使用
get_post()
函数获取文章对象。 - 构建响应数据: 创建一个包含文章信息的数组。
- 创建
WP_REST_Response
对象: 使用数组、状态码和头部信息创建一个WP_REST_Response
对象。 - 添加链接: 添加一个指向文章自身的链接。
- 返回响应对象: 返回
WP_REST_Response
对象。
12. WP_Error
类:处理错误
在上面的例子中,我们使用了 WP_Error
类来处理无效的文章 ID。WP_Error
类是 WordPress 中用于处理错误的类。它包含错误代码、错误信息和错误数据。
if ( empty( $post ) ) {
return new WP_Error( 'rest_post_invalid_id', 'Invalid post ID.', array( 'status' => 404 ) );
}
当返回 WP_Error
对象时,WordPress REST API 会自动将其转换为一个包含错误信息的 JSON 响应,并将 HTTP 状态码设置为错误代码中指定的 status
。
13. WP_REST_Controller
类:组织你的 API
虽然你可以直接使用 WP_REST_Response
类来构建 API 响应,但使用 WP_REST_Controller
类可以更好地组织你的 API 代码。WP_REST_Controller
类是一个基类,你可以继承它来创建自己的 API 控制器。
class My_Plugin_REST_Controller extends WP_REST_Controller {
/**
* Register the routes for the objects of the controller.
*/
public function register_routes() {
$namespace = 'my-plugin/v1';
$base = 'posts';
register_rest_route( $namespace, '/' . $base . '/(?P<id>d+)', array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_item' ),
'permission_callback' => array( $this, 'get_item_permissions_check' ),
'args' => array(
'id' => array(
'description' => __( 'Unique identifier for the object.' ),
'type' => 'integer',
'required' => true,
),
),
),
) );
}
/**
* Get one item from the collection.
*
* @param WP_REST_Request $request Full data about the request.
* @return WP_REST_Response|WP_Error Response on success.
*/
public function get_item( $request ) {
$post_id = $request['id'];
$post = get_post( $post_id );
if ( empty( $post ) ) {
return new WP_Error( 'rest_post_invalid_id', 'Invalid post ID.', array( 'status' => 404 ) );
}
$data = array(
'id' => $post->ID,
'title' => get_the_title( $post ),
'content' => apply_filters( 'the_content', $post->post_content ),
'link' => get_permalink( $post ),
);
$response = new WP_REST_Response( $data, 200 );
$response->header( 'Content-Type', 'application/json' );
$response->add_link( 'self', rest_url( 'my-plugin/v1/posts/' . $post->ID ) );
return $response;
}
/**
* Check if a given request has access to get one item.
*
* @param WP_REST_Request $request Full data about the request.
* @return WP_Error|bool
*/
public function get_item_permissions_check( $request ) {
// You can add permission checks here.
return true;
}
}
add_action( 'rest_api_init', function () {
$controller = new My_Plugin_REST_Controller();
$controller->register_routes();
} );
这个例子展示了如何使用 WP_REST_Controller
类来组织 API 代码,包括注册路由、定义回调函数和进行权限检查。
总结
WP_REST_Response
类是 WordPress REST API 的核心组成部分,它提供了一种简单而强大的方式来构建 API 响应。通过理解 WP_REST_Response
类的源码和使用方法,你可以创建高质量、易于使用的 REST API。
希望今天的讲解能帮助你更好地理解 WP_REST_Response
类,并在你的 WordPress REST API 开发中发挥作用。记住,代码就像魔法,只要你掌握了咒语,就能创造出令人惊叹的东西! 祝你编程愉快!