一次 WordPress REST API 内存崩溃排查实录(Sakurairo 主题)

LHabc 发布于 2026-02-20


这次排查是从一个很具体的异常开始的。我在把站点接到自动化发布流程时,发现通过应用程序密码访问 WordPress REST 接口会随机崩溃,报错一直指向内存耗尽。奇怪的是,Jetpack 相关请求是正常的,切到默认主题后核心 REST 也恢复正常。这两个现象基本把范围锁定在主题链路,而不是 WordPress 核心本身。

最初我先按常规方法看堆栈,报错在 pluggable.phpoption.phpclass-wp-hook.php 之间来回出现。这样的信号通常不代表某一个函数写错了,而更像是请求过程中加载了过重配置或者进入了异常钩子路径。结合主题代码审阅,我重点关注了三件事:主题初始化时对 iro_options 的读取、验证码相关的 authenticate 过滤器,以及主题自定义 REST 命名空间的挂载方式。

真正有效的修复思路,不是一次性“根治所有问题”,而是先保证生产可用,再把影响面收紧。我先做了保命版本,让 API 先活下来;随后把策略收敛成 v1.3,只对 /wp-json/wp/v2/* 生效,不去碰 sakura/v1jetpack/*。这样做的好处是很直接的:我需要的内容发布链路稳定了,同时主题自己的接口和其他命名空间尽量不受干扰。

v1.3 的核心代码如下。它做的事情其实很朴素:只在 wp/v2 请求里临时切默认主题,移除验证码认证钩子,并在该场景短路 iro_options 的重加载。

<?php
/**
 * Plugin Name: REST Bypass Sakurairo
 * Plugin URI: https://lhabc.me/
 * Description: v1.3 - Apply bypass only to WordPress core REST content endpoints (/wp-json/wp/v2/*).
 * Version: 1.3.0
 * Author: Alfred
 * License: GPL-2.0+
 */

if (!defined('ABSPATH')) {
    exit;
}

add_action('plugins_loaded', function () {
    $uri = isset($_SERVER['REQUEST_URI']) ? (string) $_SERVER['REQUEST_URI'] : '';

    // Narrow scope: only WordPress core content REST endpoints
    // Examples: /wp-json/wp/v2/posts, /wp-json/wp/v2/pages, /wp-json/wp/v2/media
    $is_wp_v2 = (strpos($uri, '/wp-json/wp/v2/') !== false);

    if (!$is_wp_v2) {
        return;
    }

    // 0) Force default theme only for wp/v2 REST requests (frontend unchanged)
    add_filter('pre_option_template', function ($pre) {
        return 'twentytwentyfour';
    }, 1);

    add_filter('pre_option_stylesheet', function ($pre) {
        return 'twentytwentyfour';
    }, 1);

    // 1) Bypass Sakurairo captcha/authenticate filters in wp/v2 REST context
    remove_filter('authenticate', 'CAPTCHA_CHECK', 20);
    remove_filter('authenticate', 'checkVaptchaAction', 20);
    remove_filter('authenticate', 'verify_turnstile', 20);

    // 2) Short-circuit heavy option loading in wp/v2 REST context
    add_filter('pre_option_iro_options', function ($pre) {
        return [];
    }, 1);
}, 99);

代码里每一段都很有针对性。限定 wp/v2 是为了把副作用控制在最小范围;临时切默认主题是为了绕开 Sakurairo 在 REST 场景下的重初始化路径;移除验证码钩子是为了避免 API 认证被额外逻辑干扰;短路 iro_options 是为了避免大配置在请求中触发内存膨胀。它们组合在一起,目标只有一个:让内容接口在可控前提下稳定工作。

最后的验证结果也比较干净。读取文章列表可以正常返回,草稿创建、更新、删除都能完整走通,说明发布链路已经可用。这里最重要的经验是,REST 故障很多时候并不是“接口坏了”,而是请求路径里被主题或插件塞进了并不适合 API 场景的逻辑。先恢复可用,再逐步回收临时策略,通常是更现实的工程做法。

后续我会继续往前走,把这次的旁路方案当成过渡层,再往下定位真正的触发点。等根因完全收敛后,再把这些绕过逻辑逐项退场。