如何使用 Wordpress REST API 处理未捕获的异常?

How to handle uncaught exceptions with the Wordpress REST API?

假设我有一个自定义的 Wordpress REST API 路由并且我在回调中抛出了一个未处理的异常:

register_rest_route( $namespace, "/test", [
    "methods" => "get",
    "permission_callback" => "__return_true",
    "callback" => function( $req ) {
      throw new \Exception( "Error!!" );
    }
]);

如果我查询路由,Wordpress return 会显示一个显示错误消息的 HTML 页面,这对于主题或管理​​区域来说很好,但对于 REST API我宁愿return一个WP_Error.

我想我可以在回调代码周围放置一个 try/catch 块,如下所示:

register_rest_route( $namespace, "/test", [
    "methods" => "get",
    "permission_callback" => "__return_true",
    "callback" => function( $req ) {
      try {
        throw new \Exception( "Error!!" );
      } catch( \Throwable $e ) {
        return new \WP_Error( "rest_error", $e->get_error_message() );
      }
    }
]);

但是我必须为我的所有自定义路线执行此操作,对吗?

有什么方法可以为任何自定义端点中抛出的未捕获异常设置“全局”默认响应?

我找到了一种方法 set_exception_handler。不确定这是否是最好的方法,但它似乎有效:

set_exception_handler( array( $this, "handle_uncaught_exceptions" ) );

public function handle_uncaught_exceptions( \Throwable $e ) {
   
   // First of all, log the exception
   
   log_from_exception( "errors", "alert", $e );
   
   // Now we have to return a response. By default, when an uncaught exception is thrown (fatal error) Wordpress returns 
   // an HTML page with an error message. That is fine eg. for a theme or the admin area, but for REST requests we'd rather
   // return a response that looks like a \WP_REST_Response
   
   if( is_rest_request() ) {
      
      // Set the response code to 500
      
      http_response_code(500);
      
      // Set the cross-domain headers
      
      header( "Access-Control-Allow-Origin: " . $_ENV["FRONTEND_URL"]; 
      header( "Access-Control-Allow-Credentials: true" ); 

      // Send the response
      
      $response = [
         "code" => "rest_fatal_error",
         "message" => "A fatal error occurred"
      ];
      
      wp_send_json( $response );
   
   } else {
      
      // For non-REST requests, we want to reset the default behavior, ie. sending an HTML page with an error message
      
      wp_die( $e->getMessage() );
   
   }
}

is_rest_request是一个自定义函数:

function is_rest_request() {

   $uri = $_SERVER["REQUEST_URI"]; 

   if ( empty( $uri ) ) {
      return false;
   }
   
   $restPrefix = trailingslashit( rest_get_url_prefix() ); // Resolves to "wp-json/"
   $isRestApiRequest = strpos( $uri, $restPrefix ) !== false;         

   return $isRestApiRequest; 

}