WordPress wp_send_json_success与wp_send_json_error的底层输出机制

WordPress wp_send_json_successwp_send_json_error 的底层输出机制

大家好,今天我们来深入探讨 WordPress 中用于发送 JSON 响应的两个核心函数:wp_send_json_successwp_send_json_error。这两个函数在 WordPress 开发中扮演着重要的角色,尤其是在处理 AJAX 请求和构建 REST API 时。理解它们的底层机制对于编写健壮、高效的 WordPress 代码至关重要。

1. JSON 数据格式与 HTTP 响应

在深入研究这两个函数之前,我们先回顾一下 JSON (JavaScript Object Notation) 数据格式和 HTTP 响应的基本概念。

  • JSON: 是一种轻量级的数据交换格式,易于阅读和编写,也易于机器解析和生成。它基于 JavaScript 的一个子集,但可以被多种编程语言支持。JSON 数据通常由键值对组成,可以表示简单的数据类型(如字符串、数字、布尔值)以及复杂的数据结构(如对象和数组)。

  • HTTP 响应: 当客户端(例如浏览器)向服务器发送 HTTP 请求时,服务器会返回一个 HTTP 响应。这个响应包含状态码(如 200 OK, 400 Bad Request, 500 Internal Server Error)、HTTP 头信息(例如 Content-Type, Content-Length)以及响应体。对于 AJAX 请求和 REST API,响应体通常包含 JSON 数据。

2. wp_send_json_success 函数

wp_send_json_success 函数用于发送成功的 JSON 响应。它的原型如下:

/**
 * Sends a JSON response indicating success.
 *
 * @since 4.5.0
 *
 * @param mixed $data Optional. Data to encode as JSON, then print and die. Default null.
 */
function wp_send_json_success( $data = null ) {
    $response = array( 'success' => true );

    if ( isset( $data ) ) {
        $response['data'] = $data;
    }

    wp_send_json( $response );
}

底层机制分析:

  1. 构建响应数组: 函数首先创建一个包含 'success' => true 键值对的数组 $response。这是标识成功响应的关键。

  2. 添加数据(可选): 如果提供了 $data 参数,它将被添加到 $response 数组中,键名为 'data'。这意味着你可以在成功响应中包含任何类型的数据,例如用户 ID、文章列表、更新后的配置等等。

  3. 调用 wp_send_json 函数: 最后,函数调用 wp_send_json 函数来实际发送 JSON 响应。wp_send_json 是 WordPress 中用于发送 JSON 响应的核心函数,我们稍后会详细分析它。

示例:

<?php
// 假设我们有一个函数来处理用户注册
function process_registration( $username, $password ) {
    // 验证用户名和密码
    if ( empty( $username ) || empty( $password ) ) {
        return new WP_Error( 'invalid_credentials', '用户名和密码不能为空。' );
    }

    // 创建用户
    $user_id = wp_create_user( $username, $password );

    if ( is_wp_error( $user_id ) ) {
        return $user_id; // 返回 WP_Error 对象
    }

    // 返回用户 ID 作为成功响应的数据
    return $user_id;
}

// 处理 AJAX 请求
if ( isset( $_POST['action'] ) && $_POST['action'] == 'register_user' ) {
    $username = isset( $_POST['username'] ) ? sanitize_text_field( $_POST['username'] ) : '';
    $password = isset( $_POST['password'] ) ? sanitize_text_field( $_POST['password'] ) : '';

    $result = process_registration( $username, $password );

    if ( is_wp_error( $result ) ) {
        wp_send_json_error( $result->get_error_message() );
    } else {
        wp_send_json_success( array( 'user_id' => $result ) );
    }
}
?>

在这个例子中,如果用户注册成功,process_registration 函数会返回用户 ID。wp_send_json_success 函数会将用户 ID 包装在 data 键下,并发送 JSON 响应。

输出的 JSON 结构:

{
  "success": true,
  "data": {
    "user_id": 5
  }
}

3. wp_send_json_error 函数

wp_send_json_error 函数用于发送错误的 JSON 响应。它的原型如下:

/**
 * Sends a JSON response indicating failure.
 *
 * @since 4.5.0
 *
 * @param mixed $data Optional. Data to encode as JSON, then print and die. Default null.
 * @param int   $status_code Optional. The HTTP status code to send. Default 200.
 */
function wp_send_json_error( $data = null, $status_code = null ) {
    $response = array( 'success' => false );

    if ( isset( $data ) ) {
        $response['data'] = $data;
    }

    wp_send_json( $response, $status_code );
}

底层机制分析:

  1. 构建响应数组: 函数创建一个包含 'success' => false 键值对的数组 $response。这是标识错误响应的关键。

  2. 添加数据(可选): 如果提供了 $data 参数,它将被添加到 $response 数组中,键名为 'data'。通常,$data 参数包含错误消息、错误代码或其他与错误相关的信息。

  3. 调用 wp_send_json 函数: 函数调用 wp_send_json 函数来实际发送 JSON 响应。与 wp_send_json_success 不同的是,wp_send_json_error 允许你指定一个可选的 HTTP 状态码 $status_code。默认情况下,它使用 200 OK 状态码,但这通常是不合适的,因为 200 OK 意味着请求成功。你应该使用适当的错误状态码,例如 400 Bad Request、403 Forbidden、404 Not Found 或 500 Internal Server Error。

示例:

<?php
//  在上面的注册例子中,如果用户名密码为空,将会返回错误,使用 wp_send_json_error。
// 处理 AJAX 请求
if ( isset( $_POST['action'] ) && $_POST['action'] == 'register_user' ) {
    $username = isset( $_POST['username'] ) ? sanitize_text_field( $_POST['username'] ) : '';
    $password = isset( $_POST['password'] ) ? sanitize_text_field( $_POST['password'] ) : '';

    $result = process_registration( $username, $password );

    if ( is_wp_error( $result ) ) {
        wp_send_json_error( $result->get_error_message(), 400 );
    } else {
        wp_send_json_success( array( 'user_id' => $result ) );
    }
}
?>

在这个例子中,如果 process_registration 函数返回一个 WP_Error 对象,wp_send_json_error 函数会将错误消息包装在 data 键下,并发送 JSON 响应,同时设置 HTTP 状态码为 400 Bad Request。

输出的 JSON 结构:

{
  "success": false,
  "data": "用户名和密码不能为空。"
}

HTTP 状态码: 400 Bad Request

4. wp_send_json 函数

wp_send_json 函数是 wp_send_json_successwp_send_json_error 的核心,它负责设置 HTTP 头信息并输出 JSON 数据。它的原型如下:

/**
 * Sends a JSON response to the client, including sending the proper headers.
 *
 * @since 4.1.0
 *
 * @param mixed $response Variable (usually array or object) to be encoded as JSON and sent to the client.
 * @param int   $status Optional. The HTTP status code to send. Default 200.
 */
function wp_send_json( $response = null, $status = null ) {
    // phpcs:ignore WordPress.Security.NoExitAfterRedirect.wp_send_json_exit
    @header( 'Content-Type: application/json; charset=' . get_option( 'blog_charset' ) );
    wp_send_json_options( $response, $status );
}

底层机制分析:

  1. 设置 Content-Type 头信息: 函数首先使用 header() 函数设置 Content-Type 头信息为 application/json; charset=,其中 ` 是 WordPress 博客的字符集(通常是 UTF-8)。这告诉客户端响应体包含 JSON 数据,并且使用指定的字符集进行编码。get_option( ‘blog_charset’ )`函数获取博客的字符集配置项。

  2. 调用 wp_send_json_options 函数: 函数然后调用 wp_send_json_options 函数来实际编码 JSON 数据并输出。

5. wp_send_json_options 函数

wp_send_json_options 函数是实际执行 JSON 编码和输出的函数。 它的原型如下:

/**
 * Handles JSONP callback and sends the result to the client.
 *
 * @since 4.4.0
 *
 * @param mixed $response Variable (usually array or object) to be encoded as JSON and sent to the client.
 * @param int   $status Optional. The HTTP status code to send. Default 200.
 * @param int   $options Optional. Options to be passed to json_encode(). Default 0.
 */
function wp_send_json_options( $response = null, $status = null, $options = 0 ) {
    global $wp_json_encoder;

    if ( ! is_null( $status ) ) {
        status_header( absint( $status ) );
    }

    // If available, use the faster json_encode.
    if ( function_exists( 'json_encode' ) ) {
        $encoded = json_encode( $response, $options );

        if ( false === $encoded ) {
            wp_die( 'JSON encoding failed: ' . json_last_error_msg() );
        }

        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
        echo $encoded;
    } else {
        if ( ! isset( $wp_json_encoder ) ) {
            require_once ABSPATH . WPINC . '/class-json.php';
            $wp_json_encoder = new WP_JSON_Encoder();
        }

        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
        echo $wp_json_encoder->encode( $response );
    }

    die();
}

底层机制分析:

  1. 设置 HTTP 状态码: 如果提供了 $status 参数,函数会使用 status_header() 函数设置 HTTP 状态码。status_header() 函数是 WordPress 中用于设置 HTTP 状态码的函数。

  2. JSON 编码: 函数使用 json_encode() 函数将 $response 数据编码为 JSON 字符串。json_encode() 是 PHP 内置的函数,用于将 PHP 变量转换为 JSON 字符串。$options 参数允许你传递额外的选项给 json_encode() 函数,例如 JSON_PRETTY_PRINT 用于格式化 JSON 输出。如果 json_encode() 函数失败,函数会使用 wp_die() 函数终止脚本执行并显示错误消息。

  3. 输出 JSON 数据: 函数使用 echo 语句输出 JSON 字符串。

  4. 终止脚本执行: 函数使用 die() 函数终止脚本执行。这是非常重要的,因为在发送 JSON 响应后,你通常不希望继续执行任何其他代码。

6. 总结与最佳实践

wp_send_json_successwp_send_json_error 是 WordPress 中用于发送 JSON 响应的便捷函数。它们基于 wp_send_jsonwp_send_json_options 函数,这些函数负责设置 HTTP 头信息、编码 JSON 数据并输出。

总结 wp_send_json_successwp_send_json_error 的区别:

特性 wp_send_json_success wp_send_json_error
success 键值 true false
默认状态码 200 OK 200 OK
适用场景 请求成功 请求失败

最佳实践:

  • 始终使用适当的 HTTP 状态码。对于成功的响应,使用 200 OK 或 201 Created。对于错误的响应,使用 400 Bad Request、403 Forbidden、404 Not Found 或 500 Internal Server Error 等。
  • 在错误响应中提供有用的错误消息。这有助于客户端了解发生了什么错误并采取适当的措施。
  • 对输入数据进行验证和清理,以防止安全漏洞,例如跨站脚本攻击 (XSS) 和 SQL 注入。
  • 考虑使用 JSON_PRETTY_PRINT 选项来格式化 JSON 输出,以便于调试。
  • 确保你的 WordPress 博客的字符集设置为 UTF-8,以避免编码问题。
  • 利用 WordPress 的 WP_Error 对象来处理错误,并使用 wp_send_json_error 函数发送错误响应。
  • 避免在发送 JSON 响应后继续执行任何其他代码。使用 die() 函数终止脚本执行。

7. 一个完整的例子:使用 wp_send_json_successwp_send_json_error 构建一个简单的 API 端点

假设我们想要创建一个 API 端点,允许客户端获取特定文章的信息。

<?php
/**
 * Plugin Name: Simple API Endpoint
 */

// 注册 API 端点
add_action( 'rest_api_init', 'register_article_endpoint' );

function register_article_endpoint() {
    register_rest_route(
        'myplugin/v1', // 命名空间
        '/article/(?P<id>d+)', // 路由,(?P<id>d+) 表示一个名为 id 的数字参数
        array(
            'methods'  => 'GET',
            'callback' => 'get_article_data',
            'args'     => array(
                'id' => array(
                    'validate_callback' => 'rest_validate_request_arg', // 验证参数是否有效
                    'sanitize_callback' => 'absint', // 将参数转换为整数
                ),
            ),
        )
    );
}

// API 端点回调函数
function get_article_data( $request ) {
    $article_id = $request['id'];

    // 获取文章
    $article = get_post( $article_id );

    if ( empty( $article ) ) {
        return new WP_Error( 'article_not_found', '找不到文章。', array( 'status' => 404 ) );
    }

    // 构建响应数据
    $data = array(
        'id'    => $article->ID,
        'title' => get_the_title( $article ),
        'content' => apply_filters('the_content', $article->post_content),
        'author' => get_the_author_meta( 'display_name', $article->post_author ),
        'date'  => get_the_date( 'Y-m-d H:i:s', $article ),
    );

    // 发送 JSON 响应
    return rest_ensure_response( $data ); // rest_ensure_response会自动使用wp_send_json_success或者wp_send_json_error
}

// 确保是数字
function rest_validate_request_arg( $value, $request, $param ) {
    $attributes = $request->get_attributes();
    $args = isset( $attributes['args'] ) ? $attributes['args'][$param] : array();
    $isValid = true;

    if ( isset( $args['type'] ) && 'integer' == $args['type'] ) {
        $isValid = is_numeric( $value );
    }

    return $isValid;
}

在这个例子中,我们使用 register_rest_route 函数注册了一个 API 端点 myplugin/v1/article/<id>。当客户端发送 GET 请求到这个端点时,get_article_data 函数会被调用。这个函数会获取指定 ID 的文章信息,并将其包装在 JSON 响应中发送给客户端。如果文章不存在,函数会返回一个 WP_Error 对象,rest_ensure_response 函数会自动将其转换为一个错误的 JSON 响应,并设置 HTTP 状态码为 404 Not Found。

  1. 关于 rest_ensure_response 函数

在上面的例子中,我们使用了 rest_ensure_response 函数来发送 JSON 响应。这个函数是一个非常方便的函数,它可以自动将数据转换为一个 WP_REST_Response 对象,然后使用 wp_send_json_successwp_send_json_error 函数发送 JSON 响应。 如果传入WP_Error对象,会自动使用wp_send_json_error

  1. 与早期版本 WordPress 的兼容性

在 WordPress 4.5 之前,没有 wp_send_json_successwp_send_json_error 函数。如果你需要支持更早版本的 WordPress,你可以手动构建 JSON 响应并使用 wp_send_json 函数发送。

  1. 避免常见的错误
  • 忘记设置 Content-Type 头信息: 如果你忘记设置 Content-Type 头信息为 application/json,客户端可能无法正确解析 JSON 数据。
  • 在发送 JSON 响应后继续执行代码: 这可能会导致意外的输出,并破坏 JSON 响应的格式。
  • 未正确处理错误: 如果你的代码中出现错误,但你没有正确处理它,可能会导致服务器崩溃或返回不正确的 JSON 响应。
  • 未对输入数据进行验证和清理: 这可能会导致安全漏洞。
  • 使用不正确的 HTTP 状态码: 使用不正确的 HTTP 状态码可能会导致客户端难以理解发生了什么错误。

总结一下,wp_send_json_successwp_send_json_error提供了一种规范化的方式来发送 JSON 响应,并且与 WordPress 的其他 API 很好地集成,同时需要注意正确设置 HTTP 状态码和处理错误。

发表回复

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