chore(debug): 增加 ajax 调试工具定位 admin-ajax 400 "0" 来源
- assets/js/core/ajax-debug.js:ajaxSend 记录发往 admin-ajax 的 action 与参数,ajaxError/fetch 记录失败请求的 url/status/响应 - inc/aksrt-ajax-debug.php:admin_init 时记录每个 admin-ajax 请求的 action、是否有 wp_ajax_/wp_ajax_nopriv_ 处理器、POST 载荷至 wp-content/aksrt-ajax-debug.log(handled=0 即 400 "0" 的来源) - 开关:WP_DEBUG 或 URL 带 ?aksrt_ajax_debug=1(或常量 AKSRT_AJAX_DEBUG)
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* AKSRT AJAX Debug — 排查 vendor main.min.js / zib_ajax 产生的失败请求
|
||||
*
|
||||
* 启用条件(见 inc/aksrt-ajax-debug.php):WP_DEBUG 开启,或 URL 带 ?aksrt_ajax_debug=1
|
||||
*
|
||||
* 输出:
|
||||
* - [aksrt→ajax] 所有发往 admin-ajax.php 的 jQuery 请求(含 action 与参数)
|
||||
* - [aksrt✗ajax] 所有失败的 jQuery 请求(url / data / status / responseText)
|
||||
* - [aksrt✗fetch] 所有非 2xx 的 fetch 请求
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var MAX_BODY = 500;
|
||||
|
||||
function clip(str) {
|
||||
str = String(str == null ? '' : str);
|
||||
return str.length > MAX_BODY ? str.slice(0, MAX_BODY) + '…(' + str.length + ')' : str;
|
||||
}
|
||||
|
||||
function paramsToObject(data) {
|
||||
if (!data) return null;
|
||||
if (typeof data === 'string') {
|
||||
try { return JSON.parse(data); } catch (e) { /* urlencoded */ }
|
||||
var out = {};
|
||||
new URLSearchParams(data).forEach(function (v, k) { out[k] = v; });
|
||||
return out;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
console.log('%c[aksrt] ajax 调试已开启(?aksrt_ajax_debug=1 或 WP_DEBUG)', 'color:#2abd4e;background:#16171a;padding:2px 6px;');
|
||||
|
||||
if (window.jQuery) {
|
||||
jQuery(document).ajaxSend(function (e, jqXHR, settings) {
|
||||
if (!settings || !settings.url || settings.url.indexOf('admin-ajax.php') === -1) return;
|
||||
console.log('[aksrt→ajax]', settings.type || 'GET', settings.url, paramsToObject(settings.data));
|
||||
});
|
||||
|
||||
jQuery(document).ajaxError(function (e, jqXHR, settings, thrownError) {
|
||||
console.warn('[aksrt✗ajax]', (settings && settings.type) || '?', (settings && settings.url) || '?',
|
||||
'data:', paramsToObject(settings && settings.data),
|
||||
'status:', jqXHR && jqXHR.status,
|
||||
'response:', clip(jqXHR && jqXHR.responseText),
|
||||
'thrown:', thrownError);
|
||||
// 定位触发元素:记录调用栈帮助回溯 zib_ajax 调用来源
|
||||
if (settings && settings.url && settings.url.indexOf('admin-ajax.php') !== -1) {
|
||||
console.warn('[aksrt✗ajax] 发出的 action 参数见上方 data —— 在 admin-ajax 无对应处理器时 WP 返回 400 "0"');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.warn('[aksrt] jQuery 未加载,ajax 调试仅覆盖 fetch');
|
||||
}
|
||||
|
||||
var rawFetch = window.fetch;
|
||||
if (typeof rawFetch === 'function') {
|
||||
window.fetch = function () {
|
||||
var args = arguments;
|
||||
var url = typeof args[0] === 'string' ? args[0] : (args[0] && args[0].url) || '';
|
||||
var body = args[1] && args[1].body;
|
||||
return rawFetch.apply(this, args).then(function (res) {
|
||||
if (!res.ok) {
|
||||
res.clone().text().then(function (text) {
|
||||
console.warn('[aksrt✗fetch]', res.status, url, 'body:', clip(body), 'response:', clip(text));
|
||||
}).catch(function () {});
|
||||
}
|
||||
return res;
|
||||
});
|
||||
};
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/**
|
||||
* AJAX Debug — 记录 admin-ajax 收到的每个请求,用于定位未知 action(WP 返回 400 "0")。
|
||||
*
|
||||
* 启用条件:WP_DEBUG 开启,或请求带 ?aksrt_ajax_debug=1
|
||||
* 日志位置:wp-content/aksrt-ajax-debug.log
|
||||
*
|
||||
* 每行格式:
|
||||
* [时间] action=xxx handled=0/1(nopriv) login=0/1 post={...} referer=...
|
||||
* handled=0 表示 WP 没有任何 wp_ajax_{action} / wp_ajax_nopriv_{action} 处理器,
|
||||
* 这种请求 admin-ajax 会直接 die('0') 并返回 400 —— 即控制台看到的报错来源。
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
if (!function_exists('aksrt_ajax_debug_enabled')) :
|
||||
/**
|
||||
* Whether ajax debugging is on for this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function aksrt_ajax_debug_enabled(): bool {
|
||||
if (defined('AKSRT_AJAX_DEBUG') && AKSRT_AJAX_DEBUG) {
|
||||
return true;
|
||||
}
|
||||
if (defined('WP_DEBUG') && WP_DEBUG) {
|
||||
return true;
|
||||
}
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- 调试开关,无副作用。
|
||||
return isset($_GET['aksrt_ajax_debug']) && '1' === (string) wp_unslash($_GET['aksrt_ajax_debug']);
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_ajax_debug_log')) :
|
||||
/**
|
||||
* Append a line to the ajax debug log.
|
||||
*
|
||||
* @param string $line Log line.
|
||||
*/
|
||||
function aksrt_ajax_debug_log(string $line): void {
|
||||
$file = WP_CONTENT_DIR . '/aksrt-ajax-debug.log';
|
||||
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents -- 调试日志。
|
||||
@file_put_contents($file, '[' . current_time('Y-m-d H:i:s') . '] ' . $line . "\n", FILE_APPEND | LOCK_EX);
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_ajax_debug_boot')) :
|
||||
/**
|
||||
* Hook the admin-ajax logger.
|
||||
*/
|
||||
function aksrt_ajax_debug_boot(): void {
|
||||
if (!aksrt_ajax_debug_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_action('admin_init', static function (): void {
|
||||
if (!defined('DOING_AJAX') || !DOING_AJAX) {
|
||||
return;
|
||||
}
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Recommended -- 只读记录,不修改状态。
|
||||
$action = isset($_REQUEST['action']) ? sanitize_key((string) wp_unslash($_REQUEST['action'])) : '';
|
||||
$has_logged = $action !== '' && has_action('wp_ajax_' . $action);
|
||||
$has_nopriv = $action !== '' && has_action('wp_ajax_nopriv_' . $action);
|
||||
$payload = $_POST;
|
||||
unset($payload['_wpnonce'], $payload['nonce'], $payload['_ajax_nonce']);
|
||||
aksrt_ajax_debug_log(sprintf(
|
||||
'action=%s handled=%d|%d login=%d post=%s referer=%s',
|
||||
$action !== '' ? $action : '(empty)',
|
||||
$has_logged ? 1 : 0,
|
||||
$has_nopriv ? 1 : 0,
|
||||
is_user_logged_in() ? 1 : 0,
|
||||
wp_json_encode($payload, JSON_UNESCAPED_UNICODE),
|
||||
isset($_SERVER['HTTP_REFERER']) ? (string) wp_unslash($_SERVER['HTTP_REFERER']) : ''
|
||||
));
|
||||
// phpcs:enable
|
||||
}, 1);
|
||||
}
|
||||
endif;
|
||||
|
||||
aksrt_ajax_debug_boot();
|
||||
@@ -12,6 +12,7 @@
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
// Stage 1: helpers
|
||||
require_once AKSRT_DIR . '/inc/aksrt-ajax-debug.php';
|
||||
require_once AKSRT_DIR . '/inc/helpers/aksrt-icons.php';
|
||||
require_once AKSRT_DIR . '/inc/helpers/aksrt-avatar.php';
|
||||
require_once AKSRT_DIR . '/inc/helpers/aksrt-domain-model.php';
|
||||
|
||||
@@ -119,6 +119,19 @@ trait ScriptsPart1c {
|
||||
true
|
||||
);
|
||||
|
||||
// AJAX 调试(WP_DEBUG 或 ?aksrt_ajax_debug=1):记录所有失败的
|
||||
// jQuery ajax / fetch 请求,用于定位 vendor main.min.js 的 400 "0" 来源。
|
||||
if (function_exists('aksrt_ajax_debug_enabled') && aksrt_ajax_debug_enabled()) {
|
||||
$ajax_debug_path = get_template_directory() . '/assets/js/core/ajax-debug.js';
|
||||
wp_enqueue_script(
|
||||
'aksrt-ajax-debug',
|
||||
$base_uri . '/assets/js/core/ajax-debug.js',
|
||||
['loader_js'],
|
||||
file_exists($ajax_debug_path) ? (string) filemtime($ajax_debug_path) : $version,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
if ($needs_post_list_media) {
|
||||
$grade_js = get_template_directory() . '/assets/js/grade.min.js';
|
||||
wp_enqueue_script(
|
||||
|
||||
Reference in New Issue
Block a user