资讯详情

wangeditor图片与视频上传实战:从配置到后端对接的完整指南

📅 2026/10/15 20:10:32 | 华诺云谱 👁 阅读
wangeditor图片与视频上传实战:从配置到后端对接的完整指南
做后台管理系统这些年富文本编辑器换了好几茬从早年那种密密麻麻的工具栏到后来的各种现代编辑器需求倒是从来不变能写文字能插图能放视频。特别是把 wangeditor 接入真实业务系统时图片上传和视频上传这两个能力几乎决定了这个编辑器能不能真正用起来。编辑器本身初始化很快真正让人头疼的是上传这条链路——前端要配、后端要接、回调要对、格式要准任何一个环节出问题表现都是点了没反应或者传上去了不显示。这篇文章就把我在实际项目里给 wangeditor 加图片上传和视频上传的完整过程、配置细节、后端配合方式以及踩过的坑一次讲清楚。1. 编辑器选型与上传方案的总体取舍1.1 为什么项目中最后留下了 wangeditor先说选型。市面上的富文本编辑器不算少但真正到了项目里要考虑的问题比想象中多协议是否宽松、文档是否齐全、社区是否活跃、能不能和现有前端框架无缝配合、打包体积多大、定制上传方不方便。我当时对比的几个编辑器里有的功能全面但配置复杂第一次上手容易被各种概念搞晕有的默认体验很现代但定制上传反而绕wangeditor 最打动我的地方是它的定位——国内团队维护、中文文档、API 设计直白尤其针对上传这类高频需求官方把 server 端通信格式和回调方式都定义得很清楚照着做基本不会跑偏。再说版本选择。wangeditor 4.x 是目前存量项目里最常见的版本基于原生 JavaScript 实现Vue2、Vue3、React 里都能用只是包一层封装的问题。5.x 是后来重新设计的版本对 Vue3 和 React 的支持更原生但配置项和回调方式有一些变化。我这篇文章主要以 4.x 为背景来写因为存量项目里它占比最大而且上传相关的配置思路在 5.x 里也是一脉相承的理解 4.x 的做法之后切到 5.x 只需要对照文档改配置名即可不会产生认知重构。1.2 图片和视频上传的真实业务需求上传这个需求听起来简单放到真实业务里就复杂了。图片场景至少包括文章配图、产品图、活动 banner、用户头像视频场景则包括课程视频、演示视频、产品宣传片。不同场景对文件大小、格式、存储方式、访问速度都有不同要求。图片通常控制在几 MB 以内服务端要做压缩或者至少做格式校验视频动不动几十上百 MB要考虑分片还是直传、超时怎么处理、上传进度怎么反馈。另一个隐蔽需求是编辑体验。用户插入一张图片最理想的状态是粘贴即上传、插入即回显整个过程不要跳出编辑器视频也是类似拖进来、传完、能播放。wangeditor 的配置机制可以做到这一点但需要前端把上传逻辑真正对接好否则用户传完图发现在编辑器里是个裂图或者在后台明明上传成功但页面就是空白这种体验基本等于功能没做。所以这篇博客说的支持图片和视频上传不只是配一个 server 地址那么简单而是把整个链路打通。2. 图片上传的三种实现方式和踩坑对照2.1 官方上传组件配置 server 一把梭wangeditor 4.x 的图片上传最省事的做法是让编辑器自己把文件 POST 到你配置的接口。核心配置项是uploadImgServer你只需要告诉它图片传到哪里再告诉它最大允许多大、最多一次传几张、文件字段名叫什么编辑器就会在用户选择图片后自动发请求。const editor new E(#editor) editor.config.uploadImgServer /api/upload/image editor.config.uploadImgMaxSize 5 * 1024 * 1024 editor.config.uploadImgMaxLength 5 editor.config.uploadFileName file editor.config.uploadImgParams { source: editor } editor.config.uploadImgHeaders { X-Token: localStorage.getItem(token) } editor.create()这套配置的逻辑是编辑器收集文件拼成 FormData以一个约定的字段名发给服务端然后等服务端返回一段 JSON。这里最容易被忽略的是返回格式wangeditor 对接口返回的 JSON 结构有硬性要求服务端必须返回errno和data两个字段errno为 0 表示成功data.url表示图片访问地址。如果后端返回的字段名对不上比如返回了code: 200或者data: { src: ... }前端就会认为上传失败。实际项目里我一般建议把这套官方模式作为默认方案因为它在代码层面最简洁编辑器内部已经处理了文件读取、FormData 组装、请求发送、结果回插这些琐碎逻辑。但也要清楚它的边界它不支持自定义请求库用的是编辑器内部封装的 XHR如果你需要对上传进行更精细的控制比如带进度条、断点重传、多文件并行那就得考虑自定义上传。2.2 自定义上传把控制权拿回自己手里自定义上传的场景很常见比如公司内部所有上传走统一的 OSS 直传通道签名算法在前端完成再比如上传前需要经过特定的压缩逻辑又比如文件要传到多个目标地址。这时候就要用customUpload配置项它的作用是把文件交给编辑器上传改成文件交给你自己的函数处理。editor.config.customUpload function (file, insertFn) { // file 是编辑器传出来的 File 对象 // insertFn 是你上传成功之后用来把图片插回编辑器的回调 myUploader.upload(file, { onSuccess(url) { insertFn(url, file.name, url) }, onError(err) { console.error(上传失败, err) } }) }这个模式的核心理解点在于编辑器不负责发请求了它只负责把文件交给你并给你一个insertFn。你上传成功后调用insertFn(url, alt, href)图片就会出现在编辑区域调用insertFn之前编辑器不会做任何显示动作所以如果你上传逻辑里忘了调用或者调用时机不对就会出现图片没传出去但编辑器也没反应的情况。我把这看作一种依赖倒置的设计——编辑器定义了一个插入回调接口真正的上传实现由业务方决定。这种模式虽然代码量多了一点但灵活性是质变的。我在项目里最终采用的是自定义上传 统一上传服务的方式前端所有文件上传都走同一个模块编辑器只是其中一个调用方这样维护成本反而比到处散落配置更低。2.3 base64 直插什么时候才该用wangeditor 还支持一种本地图片插入方式不传服务器直接把图片转成 base64 字符串插到编辑器内容里后续跟随 HTML 一起提交。开启方式很简单editor.config.uploadImgShowBase64 true这个思路看起来很美绕过了一切网络请求、跨域、接口对齐问题但代价非常直接base64 会把文件体积放大三分之一左右一张 3MB 的图转成 base64 可能变成 4MB 的文本塞进编辑器 DOM 里实际提交到后台的数据会非常臃肿。这还不算完编辑器内容里塞满 base64 之后整个页面的 DOM 解析和渲染都会变慢保存文章时数据库字段也会瞬间膨胀。我的原则是base64 模式只适合两种场景——第一项目处于原型阶段后端接口还没就绪先用它把编辑器的交互流程跑通第二图片本身很小比如小图标、小头像或者系统明确要求不存储原图。业务系统里的正规图片上传千万不要用 base64 替代真正的服务器上传否则上线初期可能没感觉数据量一上来你的服务器和数据库会替你付代价。3. 视频上传的完整配置与参数细节3.1 视频上传和图片上传的配置差异很多人第一次用 wangeditor 上传视频时会疑惑图片上传配得好好的视频按钮怎么点了没反应这是因为在 4.x 版本里视频上传默认没有开启 server 上传模式需要单独配置。视频上传相关的配置项是uploadVideoServer配套的参数名、大小限制和回传格式都独立于图片体系。editor.config.uploadVideoServer /api/upload/video editor.config.uploadVideoMaxSize 100 * 1024 * 1024 editor.config.uploadVideoMaxLength 1 editor.config.uploadVideoName file从语义上能看出来视频上传的配置与图片是平行的但有几个差异值得注意。视频上传默认单次只允许 1 个这个限制是合理的因为视频文件大、传输时间长用户一般不会一次插多个。视频的maxSize默认上限也比图片宽松但并不意味着你可以依赖默认值——不同业务对视频大小的容忍度差异很大有的系统限制 50MB有的可以接受 2GB这个值必须结合自己后端和存储的实际情况来定。另外视频上传成功后的回传 JSON 结构和图片相似核心也是errno和data.url。但视频在编辑器里的展示形态不一样它需要一个video标签来承载如果后端返回的地址无法被浏览器直接播放编辑器里就会出现一个空播放器框用户点播放没反应这种看起来成功但实际没用的状态比报错更让人抓狂。3.2 视频大小、格式和上传进度的控制视频上传里最容易出问题的就是大小和格式。大小控制可以在前端先拦截比如用户选了一个 300MB 的文件接口还没发出去前端就应该直接提示超出限制。wangeditor 的uploadVideoMaxSize就是在选完文件后、发送请求前做校验的配置了它用户可以立刻收到反馈而不是等请求发出去了再被服务端拒绝。格式方面我强烈建议前后端同时做校验。前端校验的目的是提前拦截明显不合法的文件避免浪费流量后端校验的目的是防绕过因为你不能假设所有请求都来自编辑器。在配置里可以用allowedFileTypes配合比如editor.config.allowedFileTypes [image/jpeg, image/png, image/gif, video/mp4, video/webm]这个配置对图片和视频会同时生效建议完整列出业务允许的 MIME 类型。这里有个细节有的浏览器对某些格式的 MIME 判断和文件扩展名不一致比如你选了 .mp4浏览器报的是video/mp4但有的安卓机拍出来的视频 MIME 可能是video/quicktime或video/x-msvideo如果你在前端把类型卡得很死会导致部分用户上传被拒。我的习惯是前端允许常见视频格式关键校验放在后端后端再根据扩展名和 MIME 双重判断。上传进度这块官方的 server 模式没有提供进度回调如果你需要进度条就得走customUploadVideo。自定义视频上传和自定义图片上传的原理一致editor.config.customUploadVideo function (file, insertFn) { uploadWithProgress(file, { onProgress(percent) { // 更新页面上的进度条 }, onSuccess(url) { insertFn(url) } }) }进度反馈对视频上传尤其重要因为视频文件大用户在没有任何反馈的情况下等十秒钟就会怀疑是不是卡死了然后开始反复点击反而制造更多重复请求。3.3 视频回显与封面处理视频上传完成后回显问题比图片复杂得多。图片回显只要url正确img标签直接渲染视频回显则要考虑播放器兼容性、视频格式编码、是否需要封面。wangeditor 的默认处理是插入一个video srcurl controls标签能不能播放完全取决于浏览器对视频编码的支持。这里有个很现实的坑你用电脑 Chrome 测试 MP4 播放一切正常但同一段视频在用户的浏览器、或者在某些移动端 WebView 里可能播放不了因为编码格式不兼容。MP4 只是一个容器里面的视频编码可能是 H.264也可能是 H.265、VP9不同浏览器对这些编码的支持程度差别很大。所以运营后台有短视频上传需求的话前端能做的有限更稳妥的方式是后端或转码服务在视频上传后统一转成兼容性最好的编码或者至少在返回 URL 时不只给原文件地址而是给一个转码后的播放地址。封面处理方面wangeditor 本身没有提供上传封面的能力但你可以通过自定义视频上传在上传视频时顺便传一张封面图然后在insertFn之前手动构造一个带video poster...的 HTML 结构再插入或者直接改insertFn传入的 URL 对应的 HTML。操作起来不复杂重点是想清楚业务上需不需要封面需要的话尽早加进上传流程而不是等视频存储完了再做二次处理返工会比较痛苦。4. 后端接口怎么配合才能稳4.1 返回数据结构必须对齐前端配置再多后端接口不按约定返回一切白搭。wangeditor 的图片上传接口成功返回格式是{ errno: 0, data: { url: https://cdn.example.com/images/2025/01/abc.png, alt: 图片描述, href: https://example.com/page } }视频上传接口成功返回格式类似data里核心字段也是url。失败时返回{ errno: 1, message: 文件大小超出限制 }我见过不少前后端联调出问题的案例根源就是后端把errno写成了code或者把data.url写成了data.path。前端拿到这种返回时编辑器内部会判定上传失败但又不清楚失败原因表现成上传没反应。所以联调时第一时间就要对齐这两个字段用浏览器开发者工具看网络返回一眼就能确认。4.2 文件校验、大小限制与静态资源处理后端接口接收上传时至少要做的三件事校验文件类型、校验文件大小、落盘或转存对象存储。校验时不要只信前端传来的 Content-Type因为这是可以伪造的更稳妥的方式是用后端的文件解析库读一下文件头比如 PNG 的文件头是固定的几个字节JPEG 也有自己的魔数MP4 则有ftyp标志。后端这样校验才能拦下真正的恶意文件前端做校验只是提升用户体验。大小限制方面如果接口部署在 Nginx 后面你在后端写了maxSize校验还不够Nginx 默认的client_max_body_size通常只有 1MB视频上传动辄几十 MB必须把这个值调大否则请求会在 Nginx 层直接被拒绝。这个坑非常隐蔽前端表现是请求发出去就 413 或 502但后端日志里什么都看不到排查一圈才发现是网关层的问题。文件存储这块要多说一句。如果项目还在起步阶段直接存本地磁盘没问题但要注意把上传目录和项目代码目录分离避免服务重启或发版时文件被清掉。如果项目有一定规模更推荐使用对象存储前端拿到的是一个 CDN 加速的 URL后端只负责生成带签名的直传凭证这种模式下 wangeditor 的customUpload就派上了用场。4.3 鉴权和跨域的一个提醒后台系统的上传接口通常需要登录态。使用官方 server 模式时通过uploadImgHeaders和uploadImgParams可以给请求带上 Token 和额外参数这个前面代码里已经演示过。需要注意的是这些配置项是静态的如果 Token 过期后前端有刷新机制你需要在上传前重新读取最新的 Token 再初始化编辑器否则编辑器里保存的旧 Token 会导致上传接口返回 401。跨域方面如果前端页面和上传接口不在同一个域名下后端必须开启 CORS并且要允许你自定义的那些请求头比如X-Token。配置 CORS 时别图省事直接*生产环境尽量写明确允许的来源域名不然上传接口就成了一个谁都能调用的开放端口。5. 完整接入示例Vue 技术栈5.1 组件封装和编辑器初始化前面原理和配置讲了不少这里给出一份可以直接参考的完整实现。我以 Vue 组件为例展示如何在上传图片和视频时统一走自定义上传逻辑把真实地址插回编辑器。template div div ideditor-container/div /div /template script import E from wangeditor export default { name: RichTextEditor, data() { return { editor: null, content: } }, mounted() { this.initEditor() }, beforeDestroy() { this.editor?.destroy() }, methods: { initEditor() { const editor new E(#editor-container) // 图片上传配置 editor.config.uploadImgMaxSize 5 * 1024 * 1024 editor.config.uploadImgMaxLength 5 editor.config.customUpload this.handleImageUpload // 视频上传配置 editor.config.uploadVideoMaxSize 100 * 1024 * 1024 editor.config.uploadVideoMaxLength 1 editor.config.customUploadVideo this.handleVideoUpload editor.create() this.editor editor editor.config.onchange (newHtml) { this.content newHtml this.$emit(change, newHtml) } }, handleImageUpload(file, insertFn) { // 这里调用统一的上传服务可以是 OSS 直传也可以是自己封装 axios uploadFile(file, { type: image }).then((url) { insertFn(url, file.name, url) }).catch((err) { console.error(图片上传失败, err) }) }, handleVideoUpload(file, insertFn) { uploadFile(file, { type: video }).then((url) { insertFn(url) }).catch((err) { console.error(视频上传失败, err) }) } } } /script这里的uploadFile是你自己封装的上传函数返回一个 Promiseresolve 时交给insertFn。整个组件把 wangeditor 封装成一个内部模块业务页面只需要监听change事件拿 HTML 内容不需要关心编辑器内部是怎么上传文件的。5.2 后端接口伪代码示例作为对照后端接口的伪代码如下方便你理解前端期望的返回结构// Node/Express 伪代码 app.post(/api/upload/image, upload.single(file), (req, res) { const file req.file // 1. 校验类型和大小 if (!isAllowedImage(file.mimetype, file.size)) { return res.json({ errno: 1, message: 图片格式或大小不符合要求 }) } // 2. 存储文件返回可访问的 URL const url saveFileToStorage(file) // 3. 按 wangeditor 约定的结构返回 res.json({ errno: 0, data: { url, alt: file.originalname, href: } }) }) app.post(/api/upload/video, upload.single(file), (req, res) { const file req.file if (!isAllowedVideo(file.mimetype, file.size)) { return res.json({ errno: 1, message: 视频格式或大小不符合要求 }) } const url saveFileToStorage(file) res.json({ errno: 0, data: { url } }) })后端逻辑并不复杂关键点就是返回结构的errno/data.url不能错以及文件校验不能省。实际项目中图片在上传后通常还会生成缩略图视频在上传后通常触发转码任务这些异步逻辑可以在saveFileToStorage里串联前端不需要感知。5.3 初始化时回显已有内容很多场景下编辑器不只是用来创建内容还要用来编辑已有内容。比如文章详情页点编辑要把数据库里已保存的 HTML 回显到编辑器里。这个需求在初始化时很容易遗漏但做法却很简单editor.create() editor.txt.html(savedHtml)这里有个需要注意的地方txt.html()必须在create()之后调用因为编辑器创建时才建立 DOM 结构。如果内容里有之前上传的图片和视频地址只要这些地址仍然可访问就能正常回显。反过来如果文件被服务端清理了或者地址过期了回显时就会显示裂图或空的播放器这种问题通常要在内容展示侧做兜底图片替换我在项目里会用一个全局的error事件处理裂图换成默认占位图用户感知会好很多。6. 实战踩坑记录与排查思路6.1 图片上传成功但编辑器里不显示这是最经典的坑打开浏览器 Network上传请求明明是 200返回的 JSON 也正确但编辑器里就是不出图。排查思路第一步不是看前端代码而是看返回的errno是什么类型。如果errno返回的是字符串0而数字0编辑器内部使用的严格等于判断可能识别不了。这种情况常见于后端语言中 JSON 序列化时把数字变成了字符串或者返回体中途被统一包装过。第二步要看data.url能不能直接在浏览器地址栏打开。如果返回的是相对路径比如/upload/xxx.png编辑器会原样写入src页面里能不能显示取决于当前页面域名和该路径能正确拼出完整地址如果返回的是绝对地址但那个地址没有配跨域或防盗链图片同样显示不出来。尤其是 CDN 开了防盗链的话编辑器里的请求带的是页面域名CDN 判断为非法来源就会返回 403图片自然裂了。6.2 视频传不上去接口也没报错另一个常见问题是点击视频按钮选择文件后完全没有任何反应Network 里也没有请求。这时候先检查是不是没有配置uploadVideoServer或customUploadVideo。在 4.x 版本中视频上传默认不启用服务端上传如果你只配置了图片上传视频按钮就形同虚设。这是文档里比较容易被忽略的默认行为我最初也在这上面耗了半天。还有一个隐蔽原因是浏览器兼容性。视频按钮依赖 FileReader 读取文件内容某些浏览器或某些安全设置下FileReader 读取大文件会失败前端没有捕获这个异常用户就感觉是点了没反应。遇到这种情况可以在customUploadVideo里对file对象加一个类型和大小日志至少能定位问题在读取阶段还是请求阶段。6.3 上传地址是 http页面却是 https混合内容问题在后台系统中很常见。如果你的页面是通过https访问的而上传接口返回的图片地址是http://浏览器会直接拦截这些资源的加载控制台会报 Mixed Content 警告。图片可能还能显示视频基本上会被浏览器拦住表现为播放器黑屏无反应。这个问题的根源往往不在 wangeditor而在存储侧。解决方式是保证所有上传接口返回的资源地址统一走https。如果你用的是对象存储可以把 CDN 域名配成 HTTPS 并开启强制跳转如果你用的是自己服务器的静态资源目录那就让 Nginx 监听 443 端口并提供证书。前端层面能做的不多但可以写一个统一处理 URL 的方法在insertFn前把http://替换成https://作为应急补丁。6.4 大视频上传超时和并发限制视频文件一大问题就多了。先看网关层Nginx 默认的proxy_read_timeout通常只有 60 秒上传一个 200MB 的视频如果网速一般很容易超时。需要把超时时间调大同时把client_max_body_size设置到合理范围我一般会设成500m或更高具体按业务上限来。再看并发限制如果你用官方 server 模式编辑器内部发请求时会有并发数量的隐式约束如果你自己实现自定义上传就要注意别在同一时刻发起太多大文件请求否则服务器的文件描述符和带宽会被瞬间打满。我之前在自定义上传里加了一个本地队列保证同时只有两个上传任务在执行其余排队这样既能保证体验又能保护后端。再补充一个关于断点续传的想法。如果业务里的视频经常超过 1GBHTTP 直传就不太合适了可以考虑切片上传——把文件切成固定大小的分片逐个上传全部传完后端合并。wangeditor 本身不提供切片上传能力但customUploadVideo这个口子允许你接入任何上传实现切片上传的逻辑完全可以放进你的自定义函数里。这也是我推荐用自定义上传的原因它在架构上留了足够的扩展空间。一点项目收尾时的体会做了几个项目之后我最大的感受是富文本编辑器的选型和使用本身并不复杂真正的复杂度都在上传二字上。wangeditor 把编辑器的编辑体验做得很顺滑但如果你只是把配置项填上而不理解背后的请求链路、返回格式、存储策略上线后总会出各种意想不到的问题。反而是那些愿意花半小时把上传链路完整捋清楚的项目后面几乎不会再为编辑器上传的琐碎问题返工。最后分享一个小技巧不管前端还是后端出了问题联调时都先打开浏览器开发者工具看 Network 里的请求和响应。wangeditor 这类组件的上传问题80% 都能在请求和响应里找到答案真正需要猜的只有那些被网关层静默拦截的请求。把这套排查习惯建立起来比记住任何具体配置都管用。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑