WordPress 5.6引入了一个框架,该框架可在对服务器的一个请求中进行一系列REST API调用。简单地说,当需要进行大量的写操作时,这对性能优化很有帮助。它还可以选择提供基本的并发控制。
注册
为了在批处理请求中使用,路由必须在注册过程中首先声明对功能的支持。例如下方代码的第5行:
register_rest_route( 'my-ns/v1', 'my-route', array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => 'my_callback', 'permission_callback' => 'my_permission_callback', 'allow_batch' => array( 'v1' => true ), ) );
如果REST API路由是使用最佳实践实现的,则声明支持应足以使该路由可通过批处理端点写入。具体来说,这些是要注意的事情:
路由必须使用该WP_REST_Request
对象来获取所有请求数据。换句话说,它不应该访问$_GET
,$_POST
或$_SERVER
变量得到参数或头。路线必须返回数据。这可以是一个WP_REST_Response
对象,一个WP_Error
对象或任何类型的JSON可序列化数据。这意味着路由一定不能直接回显响应和die()
。例如,使用wp_send_json()
或wp_die()
。路线必须是可重入的。准备好同一批路由被多次调用。
发出请求
要发送批处理,发送一个POST
请求到 https://yoursite.test/wp-json/batch/v1
使用所需的请求数组。例如,最简单的批处理请求如下所示。
{ "requests": [ { "path": "/my-ns/v1/route" } ] }
请求格式
每个请求都是一个可以接受以下属性的对象。
{ "method": "PUT", "path": "/my-ns/v1/route/1?query=param", "headers": { "My-Header": "my-value", "Multi": [ "v1", "v2" ] }, "body": { "project": "Gutenberg" } }
method
是用于请求的HTTP方法。如果省略,则使用POST
方法。path
是要调用的REST API路由。可以包含查询参数。此属性是必需的。headers
是标头名称到标头值的对象。如果标头具有多个值,则可以将其作为数组传递。body
是传递给路线的参数。填写POST
参数类型。
发现最大请求
默认情况下,REST API在一个批次中最多接受25个请求。但是,此值是可过滤的,因此可以根据服务器资源按比例放大或缩小。
function my_prefix_rest_get_max_batch_size() { return 50; } add_filter( 'rest_get_max_batch_size', 'my_prefix_rest_get_max_batch_size' );
因此,强烈建议客户提出请求前要求以发现限制。例如,发出OPTIONS
请求到batch/v1
将返回以下响应。
{ "namespace": "", "methods": [ "POST" ], "endpoints": [ { "methods": [ "POST" ], "args": { "validation": { "type": "string", "enum": [ "require-all-validate", "normal" ], "default": "normal", "required": false }, "requests": { "type": "array", "maxItems": 25, "items": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "POST", "PUT", "PATCH", "DELETE" ], "default": "POST" }, "path": { "type": "string", "required": true }, "body": { "type": "object", "properties": [], "additionalProperties": true }, "headers": { "type": "object", "properties": [], "additionalProperties": { "type": [ "string", "array" ], "items": { "type": "string" } } } } }, "required": true } } } ], "_links": { "self": [ { "href": "http://trunk.test/wp-json/batch/v1" } ] } }
该限制在endpoints[0].args.requests.maxItems
属性中指定。
回应格式
批处理端点将以与请求相同的顺序返回207
状态码和每个请求的响应。例如:
{ "responses": [ { "body": { "id": 1, "_links": { "self": [ { "href": "http://trunk.test/wp-json/my-ns/v1/route/1" } ] } }, "status": 201, "headers": { "Location": "http://trunk.test/wp-json/my-n1/v1/route/1", "Allow": "GET, POST" } } ] }
在内部,REST API信封包括它中之前每个响应responses
阵列。
验证方式
默认情况下,每个请求都是独立处理的。这意味着批处理响应可以包含一些成功的请求和一些失败的请求。有时希望仅在所有请求均有效的情况下处理批处理。例如,在古腾堡(Gutenberg),我们不想保存某些菜单项,理想情况下将保存所有菜单项,或者不保存任何菜单项。
为此,REST API允许传递的validation
模式require-all-validate
。设置此选项后,REST API将根据WP_REST_Request::has_valid_params()
和WP_REST_Request::sanitize_params()
首先检查每个请求是否有效。如果有任何请求未通过验证,则整个批次都将被拒绝。
在此示例中,发出了两个请求的批处理,第二个请求验证失败。由于responses
的顺序仍与requests
的顺序相同,因此用null
表示请求未通过验证。
{ "failed": "validation", "responses": [ null, { "body": { "code": "error_code", "message": "Invalid request data", "data": { "status": 400 } }, "status": 400, "headers": {} } ] }
注意:使用require-all-validate
不能保证所有请求都会成功。路由回调仍可能返回错误。
验证回调
在注册路由时,这些WP_REST_Request
方法使用validate_callback
和sanitize_callback
为每个参数指定。在大多数情况下,这将意味着基于架构的验证。
路线内部完成的任何验证(例如在prepare_item_for_database
方法中)都不会导致批次被拒绝。如果这是一个令人担忧的问题,建议将尽可能多的验证移到validate_callback
每个单独的参数中。例如,这可以建立在基于现有架构的验证之上。
'post' => array( 'type' => 'integer', 'minimum' => 1, 'required' => true, 'arg_options' => array( 'validate_callback' => function ( $value, $request, $param ) { $valid = rest_validate_request_arg( $value, $request, $param ); if ( is_wp_error( $valid ) ) { return $valid; } if ( ! get_post( $value ) || ! current_user_can( 'read_post', $value ) ) { return new WP_Error( 'invalid_post', __( 'That post does not exist.' ) ); } return true; } ) )
有时在执行验证时,需要请求的完整上下文。通常,此验证将在prepare_item_for_database
中完成,但WordPress 5.6引入了替代方法。注册路线时,现在可以指定validate_callback
顶层。它将接收完整的WP_REST_Request
对象,并可以返回WP_Error
实例或false
。如果参数级验证未成功,则不会执行该回调。
register_rest_route( 'my-ns/v1', 'route', array( 'callback' => '__return_empty_array', 'permission_callback' => '__return_true', 'validate_callback' => function( $request ) { if ( $request['pass1'] !== $request['pass2'] ) { return new WP_Error( 'passwords_must_match', __( 'Passwords must match.' ), array( 'status' => 400 ) ); } return true; } ) );
注意:请求验证在权限检查之前进行。在考虑是否将逻辑移至validate_callback
时要牢记这一点。
局限性
当前没有内置路由允许批处理。这将在将来的版本中添加,最有可能立即从WordPress 5.7开始。
不支持GET
请求。相反,鼓励开发人员暂时使用链接和嵌入或利用并行请求。
进一步阅读
参见#50244,[49252],[48947],[48945]。