error回调是处理404/500的唯一入口,因Layui仅在HTTP状态码为200且响应体可JSON解析时触发done;否则均进入error,且不暴露xhr实例,需手动接管XHR或查Network面板定位真实错误。
它不区分 HTTP 状态码——只要 XHR 响应状态不是 200,或者响应体无法被 JSON.parse() 成功解析,error 回调就会触发。而 done 只在「状态码为 200 且响应体是合法 JSON」时才执行。
常见现象包括:error 被调用但控制台无报错、Network 面板里看到明确的 404/500 状态码、弹窗提示“请求上传接口出现异常”。
done 里写错误处理逻辑——它根本收不到 404/500application/json 或 JSON 解析失败而进 error,而非展示后端错误信息{"code":0,"msg":"ok"},Layui 仍会进 error,因为 HTTP 状态码已非 200Layui 的 error 回调参数只有 index(上传实例索引)和 upload(上传对象),不直接暴露 xhr 实例。想获取状态码或原始响应,必须手动接管 XHR:
auto: false 关闭自动上传before 回调里构造原生 XMLHttpRequest 或用 fetch,自行处理状态码和响应体upload.success(index, res);失败则调用 upload.error(index, msg)
upload.success() 和 upload.error() 是内部方法,Layui 文档未公开,但源码中稳定存在(2.8+ 版本可用)示例片段(简化版):
upload.render({elem: '#test',auto: false,url: '/api/upload',before: function(obj){var file = this.file;var xhr = new XMLHttpRequest();xhr.open('POST', '/api/upload');xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');xhr.onload = function(){if(xhr.status === 200){try {var res = JSON.parse(xhr.responseText);upload.success(obj.index, res); // 触发 done} catch(e) {upload.error(obj.index, '响应不是合法 JSON');}} else {upload.error(obj.index, 'HTTP ' + xhr.status + ': ' + xhr.statusText);}};xhr.onerror = function(){ upload.error(obj.index, '网络错误'); };xhr.send(new FormData());}});
这是 Nginx 层面的典型静默失败:当上传大文件时,Nginx 尝试把请求体写入 client_body_temp 目录失败(比如权限不足、磁盘满、路径不存在),它不会返回 500,而是直接中断连接并返回 404 —— 此时后端代码甚至没被执行,文件当然也没存。
client_body_temp 和 Permission denied
client_body_temp_path 目录存在且 Nginx worker 进程用户(如 www-data 或 nginx)有读写权限dataFilter 只在 done 执行前对响应体做转换,它完全不参与状态码判断或网络错误捕获。也就是说,只要 XHR 没拿到 200 响应,dataFilter 根本不会运行。
dataFilter 是数据清洗工具,不是错误兜底机制dataFilter 里的代码没执行,先去 Network 看状态码,而不是怀疑 filter 写错了error 回调或手动接管 XHR真正容易被忽略的是:Layui 把「网络层失败」「协议层失败(非200)」「解析层失败(JSON异常)」全塞进同一个 error 回调,却不告诉你具体是哪一层崩了——得靠 Network 面板逐个排除。