`rest_api_init` 注册的路由返回 404:我花了两小时才发现是 "命名空间" 末尾那个斜杠在搞鬼

小助手
小助手 版主圣羽星庭 勋望元宿志愿先锋
社区管理
插件开发 75 浏览 0 回复

昨晚给插件加 REST 接口,本地 Postman 测得飞起,打包发测试环境一调——404,干净利落的 rest_no_route。路由注册代码就躺在那儿,肉眼看了十遍没毛病:

add_action( 'rest_api_init', function () {
    register_rest_route( 'myplugin/v1', '/items/(?P<id>\d+)', [
        'methods'  => 'GET',
        'callback' => [ $this, 'get_item' ],
        'permission_callback' => '__return_true',
    ] );
} );

命名空间 myplugin/v1,路径 /items/123,请求 /wp-json/myplugin/v1/items/123,逻辑上严丝合缝。但 WordPress 就是甩我 404。

先怀疑是 rest_api_init 没挂上。加了 error_log('fired'),日志里有,钩子触发了。再怀疑是其他插件把路由"覆盖"了,把代码挪到 mu-plugin、调优先级到 9999,照旧。

转折点很蠢:我把请求 URL 从浏览器地址栏复制进 Postman 时,末尾多带了一个斜杠——/wp-json/myplugin/v1/items/123/。居然 200 了。反过来再测,不带斜杠 404,带斜杠 200。

问题瞬间缩小到"命名空间"本身。翻回注册代码,我写的是:

register_rest_route( 'myplugin/v1', '/items...' );
// 实际生效的完整命名空间变成了 myplugin/v1 + /items
// 但 WordPress 内部匹配时,把命名空间当成了 myplugin/v1/ 还是 myplugin/v1 ?

扒了下 WP_REST_Server::register_route 的源码,发现命名空间处理有个细节:register_rest_route 的第一个参数如果末尾不带斜杠,WordPress 会把它和路由拼接成 myplugin/v1/items/123;但在路由查找阶段,get_route 方法对命名空间的匹配逻辑是严格前缀比对,而我在另一处代码(一个早期写的测试文件)里,曾经注册过:

register_rest_route( 'myplugin/v1/', '/health', [...] );

注意这个斜杠。myplugin/v1/myplugin/v1 在 WordPress 的路由树里是两个不同的命名空间节点。更坑的是,rest_get_url_prefix() 返回的 URL 结构里,WordPress 对末尾斜杠的容忍度并不对称——请求进来时做规范化处理,会把 /v1//items 这种双斜杠吃掉,但不会自动把 v1 补成 v1/

我的"健康检查"路由把命名空间节点"锁"成了 myplugin/v1/,后面再注册 myplugin/v1(无斜杠)的路由时,两条路实际上进了不同的桶。而 REST API 的 URL 匹配走的是规范化后的路径,导致不带斜杠的请求在 v1/ 那个桶里找不到 /items,因为 /items 被挂到了 v1(无斜杠)的下面。

修复就一行:统一命名空间格式,全部去掉末尾斜杠,把历史遗留的 myplugin/v1/ 改成 myplugin/v1。或者更保险点,自己包一层注册函数:

function myplugin_register_route( $namespace, $route, $args ) {
    $namespace = untrailingslashit( $namespace );
    register_rest_route( $namespace, $route, $args );
}

另外补个排查技巧:如果路由 404,先不要盯着自己的代码,直接全局搜项目里所有 register_rest_route,把命名空间列出来看有没有"斜杠分叉"。这比 Xdebug 还快。

还有个衍生坑:如果你用了 rest_url() 生成前端请求地址,它默认会给末尾加斜杠,但 register_rest_route 的命名空间参数不会自动处理这个差异。前后端 URL 拼接逻辑不一致时,本地能跑、线上 404 是常态。

现在我的插件里所有 REST 相关代码都强制走上面那个包装函数,命名空间常量定义在文件顶部,注释里用红字标着:末尾禁止斜杠,违者祭天

评论0
回复 · 0
还没有回复
微信客服 微信客服