Laravel中为TinyMCE图片上传添加CSRF令牌遇报错
解决Laravel中TinyMCE图片上传的419错误及后续Promise报错
问题分析
- 初始的419错误是因为Laravel的CSRF验证机制——上传请求未携带CSRF令牌,被框架拦截。
- 自定义
images_upload_handler后出现的cannot read properties of undefined (reading 'then')错误,核心原因是TinyMCE 5及以上版本要求images_upload_handler必须返回一个Promise对象,若不返回,编辑器会默认将其视为异步操作并尝试调用then方法,最终触发未定义错误。
修复步骤
1. 确保页面存在CSRF元标签
在Laravel的Blade模板头部添加以下标签(这是独立JS文件获取CSRF令牌的前提):
<meta name="csrf-token" content="{{ csrf_token() }}">
2. 修改images_upload_handler为返回Promise的结构
将原有的XHR逻辑包裹进Promise中,同时完善错误处理逻辑(调用TinyMCE提供的failure回调):
$(document).ready(function() { tinymce.init({ selector: '#body', plugins: '...', toolbar: '...', toolbar_mode: 'floating', tinycomments_mode: 'embedded', relative_urls: false, paste_data_images: true, image_title: true, automatic_uploads: true, file_picker_types: "image", // 修复后的上传处理器,返回Promise images_upload_handler: function (blobInfo, success, failure) { return new Promise(function(resolve, reject) { var xhr = new XMLHttpRequest(); xhr.withCredentials = false; xhr.open('POST', '/admin/uploadImg/'); xhr.onload = function () { if (xhr.status === 200) { try { var json = JSON.parse(xhr.responseText); if (json && typeof json.location === 'string') { success(json.location); resolve(json.location); } else { var errMsg = '返回的JSON格式无效,缺少location字段'; console.error(errMsg); failure(errMsg); reject(errMsg); } } catch (e) { var parseErr = '解析响应JSON失败: ' + e.message; console.error(parseErr); failure(parseErr); reject(parseErr); } } else { var httpErr = 'HTTP错误: ' + xhr.status; console.error(httpErr); failure(httpErr); reject(httpErr); } }; // 处理XHR网络错误 xhr.onerror = function() { var netErr = '网络请求失败,请检查连接'; console.error(netErr); failure(netErr); reject(netErr); }; var formData = new FormData(); formData.append('file', blobInfo.blob(), blobInfo.filename()); formData.append('_token', $('meta[name="csrf-token"]').attr('content')); xhr.send(formData); }); }, file_picker_callback: function (cb, value, meta) { var input = document.createElement("input"); input.setAttribute("type", "file"); input.setAttribute("accept", "image/*"); input.onchange = function () { var file = this.files[0]; var reader = new FileReader(); reader.readAsDataURL(file); reader.onload = function () { var id = "blobid" + new Date().getTime(); var blobCache = tinymce.activeEditor.editorUpload.blobCache; var base64 = reader.result.split(",")[1]; var blobInfo = blobCache.create(id, file, base64); blobCache.add(blobInfo); cb(blobInfo.blobUri(), { title: file.name }); }; }; input.click(); } }); });
3. 后端接口配合
确保/admin/uploadImg/接口正确处理上传,并返回包含location字段的JSON响应,示例:
return response()->json([ 'location' => Storage::url($uploadedFile->path()) ]);
内容的提问来源于stack exchange,提问作者yasir
相关产品推荐
相关产品推荐

