CKEditor集成Simple Upload Adapter上传图片报错Couldn't upload file求助
CKEditor图片上传报错「Couldn't upload file」排查修复方案
使用Express.js+EJS开发时,CKEditor其他功能正常,但图片上传提示「Couldn't upload file」,以下是现有代码及排查修复步骤:
现有代码
addPost.ejs
<!DOCTYPE html> <html> <head> <title><%= title %></title> <link rel='stylesheet' href='/stylesheets/style.css' /> </head> <body> <%- include('./blocks/header.ejs') %> <div class="container"> <div id="editor"> <p>Enter text</p> </div> </div> <%- include('./blocks/footer.ejs') %> <script src="ckeditor.js"></script> <script> InlineEditor .create( document.querySelector( '#editor' ), { toolbar: { items: [ 'exportPDF','exportWord', '|', 'findAndReplace', 'selectAll', '|', 'heading', '|', 'bold', 'italic', 'strikethrough', 'underline', 'code', 'subscript', 'superscript', 'removeFormat', '|', 'bulletedList', 'numberedList', 'todoList', '|', 'outdent', 'indent', '|', 'undo', 'redo', '-', 'fontSize', 'fontFamily', 'fontColor', 'fontBackgroundColor', 'highlight', '|', 'alignment', '|', 'link', 'insertImage', 'blockQuote', 'insertTable', 'mediaEmbed', 'codeBlock', 'htmlEmbed', '|', 'specialCharacters', 'horizontalLine', 'pageBreak', '|', 'textPartLanguage', '|', 'sourceEditing' ], shouldNotGroupWhenFull: true }, heading: { options: [ { model: 'paragraph', title: 'Paragraph', class: 'ck-heading_paragraph' }, { model: 'heading1', view: 'h1', title: 'Heading 1', class: 'ck-heading_heading1' }, { model: 'heading2', view: 'h2', title: 'Heading 2', class: 'ck-heading_heading2' }, { model: 'heading3', view: 'h3', title: 'Heading 3', class: 'ck-heading_heading3' }, { model: 'heading4', view: 'h4', title: 'Heading 4', class: 'ck-heading_heading4' }, { model: 'heading5', view: 'h5', title: 'Heading 5', class: 'ck-heading_heading5' }, { model: 'heading6', view: 'h6', title: 'Heading 6', class: 'ck-heading_heading6' } ] } } ) .catch( error => { console.error( error ); } ); </script> </body> </html>
src/ckeditor.js
/** * @license Copyright (c) 2014-2022, CKSource Holding sp. z o.o. All rights reserved. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license */ import InlineEditor from '@ckeditor/ckeditor5-editor-inline/src/inlineeditor.js'; import Alignment from '@ckeditor/ckeditor5-alignment/src/alignment.js'; import Autoformat from '@ckeditor/ckeditor5-autoformat/src/autoformat.js'; import AutoImage from '@ckeditor/ckeditor5-image/src/autoimage.js'; import AutoLink from '@ckeditor/ckeditor5-link/src/autolink.js'; import Autosave from '@ckeditor/ckeditor5-autosave/src/autosave.js'; import BlockQuote from '@ckeditor/ckeditor5-block-quote/src/blockquote.js'; import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold.js'; import CloudServices from '@ckeditor/ckeditor5-cloud-services/src/cloudservices.js'; import Code from '@ckeditor/ckeditor5-basic-styles/src/code.js'; import CodeBlock from '@ckeditor/ckeditor5-code-block/src/codeblock.js'; import Essentials from '@ckeditor/ckeditor5-essentials/src/essentials.js'; import FindAndReplace from '@ckeditor/ckeditor5-find-and-replace/src/findandreplace.js'; import FontBackgroundColor from '@ckeditor/ckeditor5-font/src/fontbackgroundcolor.js'; import FontColor from '@ckeditor/ckeditor5-font/src/fontcolor.js'; import FontFamily from '@ckeditor/ckeditor5-font/src/fontfamily.js'; import FontSize from '@ckeditor/ckeditor5-font/src/fontsize.js'; import GeneralHtmlSupport from '@ckeditor/ckeditor5-html-support/src/generalhtmlsupport.js'; import Heading from '@ckeditor/ckeditor5-heading/src/heading.js'; import Highlight from '@ckeditor/ckeditor5-highlight/src/highlight.js'; import HorizontalLine from '@ckeditor/ckeditor5-horizontal-line/src/horizontalline.js'; import Image from '@ckeditor/ckeditor5-image/src/image.js'; import ImageCaption from '@ckeditor/ckeditor5-image/src/imagecaption.js'; import ImageInsert from '@ckeditor/ckeditor5-image/src/imageinsert.js'; import ImageResize from '@ckeditor/ckeditor5-image/src/imageresize.js'; import ImageStyle from '@ckeditor/ckeditor5-image/src/imagestyle.js'; import ImageToolbar from '@ckeditor/ckeditor5-image/src/imagetoolbar.js'; import ImageUpload from '@ckeditor/ckeditor5-image/src/imageupload.js'; import Indent from '@ckeditor/ckeditor5-indent/src/indent.js'; import IndentBlock from '@ckeditor/ckeditor5-indent/src/indentblock.js'; import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic.js'; import Link from '@ckeditor/ckeditor5-link/src/link.js'; import LinkImage from '@ckeditor/ckeditor5-link/src/linkimage.js'; import List from '@ckeditor/ckeditor5-list/src/list.js'; import ListProperties from '@ckeditor/ckeditor5-list/src/listproperties.js'; import MediaEmbed from '@ckeditor/ckeditor5-media-embed/src/mediaembed.js'; import MediaEmbedToolbar from '@ckeditor/ckeditor5-media-embed/src/mediaembedtoolbar.js'; import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph.js'; import PasteFromOffice from '@ckeditor/ckeditor5-paste-from-office/src/pastefromoffice.js'; import RemoveFormat from '@ckeditor/ckeditor5-remove-format/src/removeformat.js'; import SpecialCharacters from '@ckeditor/ckeditor5-special-characters/src/specialcharacters.js'; import SpecialCharactersArrows from '@ckeditor/ckeditor5-special-characters/src/specialcharactersarrows.js'; import SpecialCharactersCurrency from '@ckeditor/ckeditor5-special-characters/src/specialcharacterscurrency.js'; import SpecialCharactersEssentials from '@ckeditor/ckeditor5-special-characters/src/specialcharactersessentials.js'; import SpecialCharactersLatin from '@ckeditor/ckeditor5-special-characters/src/specialcharacterslatin.js'; import SpecialCharactersMathematical from '@ckeditor/ckeditor5-special-characters/src/specialcharactersmathematical.js'; import SpecialCharactersText from '@ckeditor/ckeditor5-special-characters/src/specialcharacterstext.js'; import Strikethrough from '@ckeditor/ckeditor5-basic-styles/src/strikethrough.js'; import Style from '@ckeditor/ckeditor5-style/src/style.js'; import Subscript from '@ckeditor/ckeditor5-basic-styles/src/subscript.js'; import Superscript from '@ckeditor/ckeditor5-basic-styles/src/superscript.js'; import Table from '@ckeditor/ckeditor5-table/src/table.js'; import TableCaption from '@ckeditor/ckeditor5-table/src/tablecaption.js'; import TableCellProperties from '@ckeditor/ckeditor5-table/src/tablecellproperties'; import TableColumnResize from '@ckeditor/ckeditor5-table/src/tablecolumnresize.js'; import TableProperties from '@ckeditor/ckeditor5-table/src/tableproperties'; import TableToolbar from '@ckeditor/ckeditor5-table/src/tabletoolbar.js'; import TextTransformation from '@ckeditor/ckeditor5-typing/src/texttransformation.js'; import Title from '@ckeditor/ckeditor5-heading/src/title.js'; import Underline from '@ckeditor/ckeditor5-basic-styles/src/underline.js'; import WordCount from '@ckeditor/ckeditor5-word-count/src/wordcount.js'; import SimpleUploadAdapter from '@ckeditor/ckeditor5-upload/src/adapters/simpleuploadadapter'; class Editor extends InlineEditor {} // Plugins to include in the build. Editor.builtinPlugins = [ Alignment, Autoformat, AutoImage, AutoLink, Autosave, BlockQuote, Bold, CloudServices, Code, CodeBlock, Essentials, FindAndReplace, FontBackgroundColor, FontColor, FontFamily, FontSize, GeneralHtmlSupport, Heading, Highlight, HorizontalLine, Image, ImageCaption, ImageInsert, ImageResize, ImageStyle, ImageToolbar, ImageUpload, Indent, IndentBlock, Italic, Link, LinkImage, List, ListProperties, MediaEmbed, MediaEmbedToolbar, Paragraph, PasteFromOffice, RemoveFormat, SpecialCharacters, SpecialCharactersArrows, SpecialCharactersCurrency, SpecialCharactersEssentials, SpecialCharactersLatin, SpecialCharactersMathematical, SpecialCharactersText, Strikethrough, Style, Subscript, Superscript, Table, TableCaption, TableCellProperties, TableColumnResize, TableProperties, TableToolbar, TextTransformation, Title, Underline, WordCount, SimpleUploadAdapter ]; // Editor configuration. Editor.defaultConfig = { toolbar: { items: [ 'heading', '|', 'bold', 'italic', 'underline', 'strikethrough', 'link', 'bulletedList', 'numberedList', '|', 'alignment', 'outdent', 'indent', '|', 'codeBlock', 'imageUpload', 'imageInsert', 'blockQuote', 'insertTable', 'mediaEmbed', 'undo', 'redo', '-', 'fontBackgroundColor', 'fontColor', 'fontFamily', 'fontSize', '|', 'horizontalLine', 'specialCharacters', 'highlight', 'removeFormat', 'superscript', 'subscript', '|', 'findAndReplace', 'style' ], shouldNotGroupWhenFull: true }, language: 'ru', image: { toolbar: [ 'imageTextAlternative', 'imageStyle:inline', 'imageStyle:block', 'imageStyle:side', 'linkImage' ], upload: { types: [ 'jpg', 'jpeg', 'png', 'gif', 'bmp' ] } }, table: { contentToolbar: [ 'tableColumn', 'tableRow', 'mergeTableCells', 'tableCellProperties', 'tableProperties' ] }, simpleUpload: { uploadUrl: 'http://localhost:3000', withCredentials: true, headers: { 'X-CSRF-TOKEN': 'CSRF-Token', Authorization: 'Bearer <JSON Web Token>' } } }; export default Editor;
排查修复步骤
补全后端文件上传接口
当前simpleUpload.uploadUrl指向根路径,但Express默认不处理文件上传请求,需新增POST接口:// Express路由示例 const express = require('express'); const multer = require('multer'); const router = express.Router(); // 配置文件存储目录和命名规则 const storage = multer.diskStorage({ destination: (req, file, cb) => { cb(null, 'public/uploads/'); // 确保该目录已创建且有读写权限 }, filename: (req, file, cb) => { cb(null, Date.now() + '-' + file.originalname); } }); const upload = multer({ storage: storage }); // 接收CKEditor上传请求的接口 router.post('/upload', upload.single('upload'), (req, res) => { if (!req.file) { return res.status(400).json({ error: '未上传文件' }); } // 返回CKEditor要求的JSON格式 res.json({ url: `/uploads/${req.file.filename}` }); }); module.exports = router;同时将
simpleUpload.uploadUrl修改为http://localhost:3000/upload。清理无效请求头配置
当前配置的X-CSRF-TOKEN和Authorization为占位值,若后端未开启对应验证,直接删除这两个配置项,避免请求被拦截;若需验证,替换为实际有效令牌。处理跨域问题
若前端与后端端口/域名不一致,需在Express中配置CORS:const cors = require('cors'); app.use(cors({ origin: 'http://你的前端地址', credentials: true }));同域环境下可将
withCredentials设为false。检查目录权限
确保后端配置的文件存储目录(如public/uploads/)存在,且Node进程拥有读写权限,否则会导致文件写入失败。同步前后端上传配置
前端初始化Editor时,需确保simpleUpload配置与后端接口一致,可在create方法中补充配置:InlineEditor.create(document.querySelector('#editor'), { // 原有配置... simpleUpload: { uploadUrl: 'http://localhost:3000/upload' } })
内容的提问来源于stack exchange,提问作者Timofey Potapov
相关产品推荐
相关产品推荐

