详解 WordPress `WP_REST_Request` 类的源码:如何封装 HTTP 请求并提供参数访问。

WordPress WP_REST_Request 类源码详解:HTTP 请求封装与参数访问(大师级讲座)

大家好,我是你们的 WordPress 代码老司机,今天咱们来聊聊 WordPress REST API 的核心部件之一:WP_REST_Request 类。这玩意儿就像 REST API 的运输大队长,负责把 HTTP 请求的信息打包好,送到各个处理函数手里。

准备好了吗?系好安全带,咱们发车!

1. WP_REST_Request 是个啥?(类比解释)

想象一下,你点了个外卖,外卖小哥手里拿着订单。这个 WP_REST_Request 就相当于那个订单,它包含了:

  • 送货地址 (URL): 请求的 API 端点 (例如 /wp/v2/posts)
  • 点了啥 (Parameters): 你提交的数据,比如文章标题、内容等等
  • 怎么付钱 (HTTP Method): GET, POST, PUT, DELETE 等等
  • 给外卖小哥的备注 (Headers): 用户认证信息、内容类型等等

总之,它把 HTTP 请求的所有重要信息都封装起来了,方便 WordPress 处理。

2. 源码结构概览

让我们打开 wp-includes/rest-api/class-wp-rest-request.php 文件,看看这辆“运输大队长”的内部结构。

<?php
/**
 * REST API: WP_REST_Request class
 *
 * @package WordPress
 * @subpackage REST_API
 * @since 4.4.0
 */

/**
 * Core class used to implement a REST request object.
 *
 * @since 4.4.0
 */
class WP_REST_Request {

    /**
     * HTTP method for the request.
     *
     * @since 4.4.0
     * @access protected
     * @var string
     */
    protected $method;

    /**
     * Route matched for the request.
     *
     * @since 4.4.0
     * @access protected
     * @var string
     */
    protected $route;

    /**
     * Request parameters.
     *
     * @since 4.4.0
     * @access protected
     * @var array
     */
    protected $params = array();

    /**
     * Attributes for the route.
     *
     * @since 4.4.0
     * @access protected
     * @var array
     */
    protected $attributes = array();

    /**
     * Headers for the request.
     *
     * @since 4.4.0
     * @access protected
     * @var array
     */
    protected $headers = array();

    /**
     * Cookies for the request.
     *
     * @since 4.4.0
     * @access protected
     * @var array
     */
    protected $cookies = array();

    /**
     * Files for the request.
     *
     * @since 4.7.0
     * @access protected
     * @var array
     */
    protected $files = array();

    // ... (其他方法)
}

可以看到,这个类定义了一些关键的属性:

属性名 类型 描述
$method string HTTP 请求方法 (GET, POST, PUT, DELETE 等)
$route string 匹配的 REST API 路由 (例如 /wp/v2/posts)
$params array 请求参数,包括 URL 参数、POST 数据等等
$attributes array 路由的属性,通常包含该路由的 schema 信息
$headers array HTTP 请求头
$cookies array HTTP Cookies
$files array 上传的文件信息

3. 构造函数:__construct()

WP_REST_Request 对象的创建通常不是手动进行的。REST API 框架会根据接收到的 HTTP 请求自动创建并填充这个对象。但了解构造函数可以帮助我们理解如何手动创建和使用它。

    /**
     * Constructor.
     *
     * @since 4.4.0
     *
     * @param string $method Optional. HTTP method. Defaults to 'GET'.
     * @param string $route  Optional. The route matched for the request.
     */
    public function __construct( $method = 'GET', $route = null ) {
        $this->set_method( $method );
        if ( ! empty( $route ) ) {
            $this->set_route( $route );
        }
    }

构造函数接收两个可选参数:HTTP 方法和路由。你可以这样创建一个 WP_REST_Request 对象:

$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );

4. 设置和获取属性的方法

WP_REST_Request 类提供了一系列 set_*()get_*() 方法来设置和获取对象的属性。咱们挑几个重要的看看:

4.1 set_method()get_method()

设置和获取 HTTP 请求方法。

    /**
     * Sets the HTTP method for the request.
     *
     * @since 4.4.0
     *
     * @param string $method HTTP method.
     */
    public function set_method( $method ) {
        $this->method = strtoupper( $method );
    }

    /**
     * Gets the HTTP method for the request.
     *
     * @since 4.4.0
     *
     * @return string HTTP method.
     */
    public function get_method() {
        return $this->method;
    }

示例:

$request = new WP_REST_Request();
$request->set_method( 'PUT' );
echo $request->get_method(); // 输出:PUT

4.2 set_route()get_route()

设置和获取请求的路由。

    /**
     * Sets the route for the request.
     *
     * @since 4.4.0
     *
     * @param string $route Route matched for the request.
     */
    public function set_route( $route ) {
        $this->route = $route;
    }

    /**
     * Gets the route for the request.
     *
     * @since 4.4.0
     *
     * @return string Route matched for the request.
     */
    public function get_route() {
        return $this->route;
    }

示例:

$request = new WP_REST_Request();
$request->set_route( '/wp/v2/posts/123' );
echo $request->get_route(); // 输出:/wp/v2/posts/123

4.3 参数管理:set_param(), get_param(), get_params()

这组方法用于管理请求参数,是最核心的部分之一。

    /**
     * Sets a single parameter for the request.
     *
     * @since 4.4.0
     *
     * @param string $key   Parameter name.
     * @param mixed  $value Parameter value.
     */
    public function set_param( $key, $value ) {
        $this->params[ $key ] = $value;
    }

    /**
     * Gets a single parameter for the request.
     *
     * @since 4.4.0
     *
     * @param string $key Parameter name.
     * @return mixed Parameter value, or null if not set.
     */
    public function get_param( $key ) {
        if ( isset( $this->params[ $key ] ) ) {
            return $this->params[ $key ];
        }

        return null;
    }

    /**
     * Retrieves all parameters for the request.
     *
     * @since 4.4.0
     *
     * @return array Parameters for the request.
     */
    public function get_params() {
        return $this->params;
    }

示例:

$request = new WP_REST_Request();
$request->set_param( 'title', 'Hello World' );
$request->set_param( 'content', 'This is my first post.' );

echo $request->get_param( 'title' ); // 输出:Hello World
print_r( $request->get_params() );
// 输出:
// Array
// (
//     [title] => Hello World
//     [content] => This is my first post.
// )

4.4 批量设置参数:set_query_params(), set_body_params(), set_default_params()

为了更方便地设置参数,WP_REST_Request 还提供了批量设置参数的方法。

  • set_query_params( array $params ): 设置 URL 查询参数 (例如 ?title=Hello&content=World)
  • set_body_params( array $params ): 设置请求体参数 (通常用于 POST/PUT 请求)
  • set_default_params( array $params ): 设置默认参数,如果参数已经存在,则不会被覆盖。
    /**
     * Sets query parameters.
     *
     * @since 4.4.0
     *
     * @param array $params Query parameters.
     */
    public function set_query_params( $params ) {
        $this->params = array_merge( $this->params, $params );
    }

    /**
     * Sets body parameters.
     *
     * @since 4.4.0
     *
     * @param array $params Body parameters.
     */
    public function set_body_params( $params ) {
        $this->params = array_merge( $this->params, $params );
    }

    /**
     * Sets default parameters.
     *
     * @since 4.4.0
     *
     * @param array $params Default parameters.
     */
    public function set_default_params( $params ) {
        $this->params = array_merge( $params, $this->params );
    }

示例:

$request = new WP_REST_Request();
$request->set_query_params( array( 'title' => 'Hello', 'status' => 'draft' ) );
$request->set_body_params( array( 'content' => 'This is a test.' ) );

print_r( $request->get_params() );
// 输出:
// Array
// (
//     [title] => Hello
//     [status] => draft
//     [content] => This is a test.
// )

4.5 Header管理:get_headers(), get_header()

这两个方法用于获取 HTTP 请求头信息。

    /**
     * Retrieves all headers for the request.
     *
     * @since 4.4.0
     *
     * @return array Headers for the request.
     */
    public function get_headers() {
        return $this->headers;
    }

    /**
     * Retrieves a single header for the request.
     *
     * @since 4.4.0
     *
     * @param string $key Header name.
     * @return string Header value, or null if not set.
     */
    public function get_header( $key ) {
        $key = strtolower( $key );
        if ( isset( $this->headers[ $key ] ) ) {
            return $this->headers[ $key ];
        }

        return null;
    }

示例:

$request = new WP_REST_Request();
$request->headers = array( 'content-type' => 'application/json', 'authorization' => 'Bearer xxx' ); // 通常由 REST API 框架自动填充

echo $request->get_header( 'content-type' ); // 输出:application/json
print_r( $request->get_headers() );
// 输出:
// Array
// (
//     [content-type] => application/json
//     [authorization] => Bearer xxx
// )

注意: WP_REST_Request 类本身并不负责解析 HTTP 请求头。这些信息通常由 WordPress 的 HTTP 请求处理机制(例如 $_SERVER 变量)提供,然后被 REST API 框架填充到 $headers 属性中。

4.6 文件上传:get_file_params()

从 WordPress 4.7 开始,WP_REST_Request 支持文件上传。get_file_params() 方法用于获取上传的文件信息。

    /**
     * Retrieves all files for the request.
     *
     * @since 4.7.0
     *
     * @return array Files for the request.
     */
    public function get_file_params() {
        return $this->files;
    }

文件上传的处理比较复杂,涉及 $_FILES 变量、临时文件等等。这里我们只简单了解一下 get_file_params() 的作用。

5. 参数合并的优先级

当同一个参数通过不同的方式传递(例如 URL 查询参数和请求体参数),WP_REST_Request 会按照一定的优先级进行合并。一般来说,优先级顺序如下(从高到低):

  1. 请求体参数 (set_body_params())
  2. URL 查询参数 (set_query_params())
  3. 默认参数 (set_default_params())

也就是说,如果同一个参数既存在于请求体中,又存在于 URL 查询字符串中,那么请求体中的值会覆盖 URL 查询字符串中的值。

6. 如何在 REST API 端点中使用 WP_REST_Request

在自定义 REST API 端点中,你通常会在回调函数中接收到一个 WP_REST_Request 对象。你可以使用上面介绍的方法来获取请求的信息。

add_action( 'rest_api_init', function () {
  register_rest_route( 'myplugin/v1', '/custom-endpoint', array(
    'methods'  => 'POST',
    'callback' => 'my_custom_endpoint_callback',
  ) );
} );

function my_custom_endpoint_callback( WP_REST_Request $request ) {
  $title = $request->get_param( 'title' );
  $content = $request->get_param( 'content' );

  if ( empty( $title ) || empty( $content ) ) {
    return new WP_Error( 'missing_params', 'Title and content are required.', array( 'status' => 400 ) );
  }

  // 创建文章
  $post_id = wp_insert_post( array(
    'post_title'   => $title,
    'post_content' => $content,
    'post_status'  => 'publish',
  ) );

  if ( is_wp_error( $post_id ) ) {
    return $post_id;
  }

  return rest_ensure_response( array( 'id' => $post_id, 'message' => 'Post created successfully.' ) );
}

在这个例子中,my_custom_endpoint_callback 函数接收一个 WP_REST_Request 对象,然后使用 get_param() 方法获取 titlecontent 参数。

7. 总结

WP_REST_Request 类是 WordPress REST API 的核心组件,它封装了 HTTP 请求的所有重要信息,并提供了方便的方法来访问这些信息。理解 WP_REST_Request 类的用法,可以帮助你更好地开发自定义 REST API 端点,并处理各种类型的 HTTP 请求。

总的来说,WP_REST_Request 类就像一个精心设计的工具箱,里面装满了处理 HTTP 请求的各种工具。熟练掌握这些工具,你就可以在 WordPress REST API 的世界里自由驰骋啦!

记住,代码就像女朋友,需要你好好了解她,才能更好地使用她!

希望今天的讲座对大家有所帮助! 谢谢!

发表回复

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