资讯动态

IIS轻量级音视频服务实战:零代码部署本地媒体站

发布时间:2026/10/17 15:47:42 来源:尧图企业网站定制
1. 项目概述这不是建站教程而是一次面向内容创作者的“轻量级媒体服务实战”你搜“用IIS建音乐视频网站”大概率会看到两类内容一类是教你怎么点开IIS管理器、添加网站、绑定端口的纯界面操作流水账另一类则直接跳到“推荐用WordPress插件”或者“上云服务器更省心”把IIS当成一个过时的、只配给老系统打补丁的工具。但真实情况是——在某高校数字媒体实验室、某独立音乐人工作室、某社区文化站的实际项目中IIS至今仍是部署本地化音视频展示平台最稳、最可控、最不依赖第三方服务的选择。它不追求千万并发但能保证20台终端同时点播《民谣现场实录》不卡顿它不提供算法推荐但能让访客点开网页就自动播放一首3分钟吉他独奏全程无跳转、无广告、无登录墙。这个项目标题里的“博主教你”不是指网红博主而是指一位常年帮小型文化机构做技术落地的实操派从业者——我本人。过去三年我用IIS搭过7个不同形态的音视频站点有纯HTML5音频库有带简单后台的MV轮播页也有接入本地NAS存储、支持按歌手/年份筛选的校园广播站系统。它们共同的特点是零外部CDN依赖、全静态资源托管、Windows Server或甚至Win10专业版就能跑、管理员不用懂PHP也能改页面。所以这篇内容不是讲“IIS是什么”而是直奔“怎么让IIS真正扛起音视频服务这根担子”——从MIME类型配置的底层逻辑到HLS分片的兼容性取舍再到为什么连一个简单的MP4文件都可能在IE和Edge里表现迥异。如果你正为社团活动需要一个能放演出录像的网页、为孩子钢琴考级录一段可分享的视频集、或者只是想把硬盘里几百首无损FLAC整理成可点击试听的目录那接下来的内容就是你抄作业时真正能用上的部分。2. 核心设计思路为什么坚持用IIS而不是Node.js或Nginx2.1 不是技术怀旧而是场景刚性约束下的最优解很多人一听到“IIS”就下意识觉得“重”“老”“Windows专属”但恰恰是这些“缺点”在特定场景里成了不可替代的优势。我们先看三个真实需求案例案例A某社区老年大学需要一个内部网站供学员课后回看书法教学视频。硬件是一台5年前的戴尔OptiPlex预装Win10专业版IT人员只会用远程桌面和记事本。要求打开浏览器输入http://192.168.1.100就能看不装任何插件不注册账号不连外网。案例B某独立音乐人要发布新专辑试听页所有音源存在本地移动硬盘NTFS格式希望访客点开网页就能顺序播放10首WAV文件且能显示专辑封面和曲目信息。要求不上传到任何云盘不压缩音质不依赖第三方播放器SDK。案例C某高校学生会搭建迎新视频站素材来自各班提交的MP4手机拍摄视频总容量约120GB。要求校内局域网访问延迟低于200ms支持同时30人在线观看同一段迎新VCR管理员能用Excel批量更新视频标题和描述。这三个需求如果强行套用主流建站方案会立刻踩坑用Node.js写一个Express静态服务行但得装Node环境、写路由、处理跨域、自己写播放页HTML——对案例A的管理员来说光是“npm install”这一步就卡死在CMD窗口里。用NginxLinux发行版部署没问题但案例B的音乐人电脑是Win10硬装WSL2再配Nginx等于让一个只会用Audition剪辑的人去调试Linux内核参数。用WordPress模板好看但默认不支持原生WAV播放浏览器兼容性差上传大文件要调php.ini而案例C的120GB素材根本不可能全导入数据库。IIS的不可替代性就体现在它和Windows生态的“零摩擦耦合”上它是Win10/11专业版及Server系统自带组件启用只需勾选一个复选框无需下载安装包它的管理界面inetmgr是图形化操作添加网站、绑定IP、设置默认文档全部鼠标点选完成它对NTFS权限体系原生支持案例B的移动硬盘插上即识别IIS直接读取不用考虑Linux下的挂载权限问题它的MIME类型映射表是系统级配置改一次所有网站生效不像Apache需要每个.htaccess单独写。提示IIS不是万能的它不适合做高并发直播、不擅长动态生成缩略图、不内置用户系统。但如果你的需求本质是“把已有的音视频文件用最简路径暴露给指定人群”那IIS就是那个“少即是多”的答案。2.2 架构极简主义拒绝过度设计聚焦核心链路很多失败的IIS音视频站败在一开始就想着“功能完整”。我见过最典型的错误是花三天时间研究如何用ASP.NET写一个带登录、评论、收藏的后台结果最后发现用户真正需要的只是一页带封面图的MP3列表。所以本项目的架构设计严格遵循“三不原则”不引入动态语言全程不写一行C#或VB.NET代码。所有页面用纯HTMLCSSJavaScript实现数据源是JSON文件非数据库播放控制用原生HTML5audio和video标签。不依赖外部CDN或JS库Bootstrap、jQuery、Video.js等统统不用。播放器样式自己用CSS重写进度条拖拽逻辑用原生JS事件监听timeupdate、seeking这样即使断网页面照样能播。不强制统一编码格式不规定必须用MP4/H.264或MP3而是通过IIS的MIME类型配置让服务器“告诉浏览器”这个文件该怎么解析。一个.flac文件只要IIS返回audio/flac头现代浏览器就认一个.mkv文件虽然Chrome不原生支持但我们可以用FFmpeg提前转成WebM再让IIS返回video/webm。最终落地的结构只有四层D:\MusicSite\ ├── index.html # 首页含播放器容器和曲目列表 ├── assets\ # 静态资源 │ ├── css\ # 自定义样式表 │ ├── js\ # 原生JS播放控制脚本 │ └── images\ # 封面图、图标 ├── data\ # 数据源非数据库 │ └── songs.json # 曲目元数据标题、时长、文件路径、封面相对地址 └── media\ # 音视频文件实际存放目录可映射到NAS或移动硬盘 ├── audio\ │ ├── song01.flac │ └── song02.wav └── video\ ├── intro.mp4 └── live_2023.webm这个结构的好处是管理员增删一首歌只需往media\audio\里扔文件再在songs.json里加一行JSON刷新网页就生效。没有缓存清理没有数据库迁移没有版本回滚——就像管理一个普通文件夹一样直观。2.3 性能与体验的平衡点为什么放弃HLS/DASH选择渐进式下载现在提到视频网站第一反应是HLS.m3u8.ts或DASH.mpd.mp4。但这两个方案在IIS轻量部署场景里是典型的“杀鸡用牛刀”。我们来算一笔账HLS分片成本一个10分钟的MP4用FFmpeg切片成4秒一段的TS文件会产生150个碎片文件。IIS要为每个.ts单独返回video/MP2TMIME头还要维护.m3u8索引文件的更新。当你要管理500首歌时就是75000个文件光是文件系统遍历就拖慢响应。浏览器兼容性陷阱Safari原生支持HLSChrome从95版开始弃用需用Media Source ExtensionsMSE手动加载而MSE在低内存设备如老款Surface上极易触发QuotaExceededError。首屏等待时间HLS必须等第一个TS片段加载完才开始播放而渐进式下载Progressive Download的MP4浏览器拿到前几KB的moov box就能启动解码实测首帧时间快1.8秒。所以本项目采用“渐进式下载关键帧优化”策略所有MP4文件用FFmpeg预处理确保moov原子在文件开头-movflags faststart视频分辨率统一为1280×720够看清字幕又不压垮千兆内网音频统一用AAC-LC编码比MP3更小体积比Opus更广兼容IIS开启静态内容压缩gzip对.json、.css、.js自动压缩但不对.mp4和.flac启用压缩——因为二进制文件压缩率极低反而增加CPU负担。实测数据在千兆局域网下一个200MB的720p MP4从点击播放到画面出现平均耗时1.2秒IIS 10 Win10而同等条件下HLS方案平均为3.4秒。这1.2秒就是老年大学学员愿意继续点开第二段教学视频还是直接关掉网页的关键阈值。3. 核心细节解析MIME类型、文件头、播放器兼容性三重门3.1 MIME类型不是“填空题”而是浏览器解析的“宪法”很多IIS新手以为只要把文件放在网站目录下浏览器就能播。结果发现MP3能播WAV点开是下载FLAC直接报404。根源不在文件本身而在IIS返回的HTTP响应头里缺了关键一句Content-Type: audio/wav这句头信息就是浏览器判断“这个文件我该用哪个解码器打开”的唯一依据。IIS默认只认识几十种常见类型如.html→text/html.jpg→image/jpeg对音视频格式支持极其保守。比如.wav默认未注册 → 返回application/octet-stream→ 浏览器不认识直接下载.flac默认未注册 → 同样返回application/octet-stream.webm在IIS 8.5才被加入默认列表旧版需手动添加。所以第一步必须手工补全MIME映射表。操作路径IIS管理器 → 服务器节点 → “MIME类型” → 右侧“添加”扩展名MIME类型说明.wavaudio/wav注意不是audio/x-wav后者是过时写法.flacaudio/flacChrome/Firefox/Edge均支持Safari 14.1支持.webmvideo/webmVP9视频Opus音频体积比MP4小30%.m4aaudio/mp4AAC音频封装比MP3更高效.mkvvideo/x-matroska谨慎添加仅Chrome支持Firefox需插件注意添加后必须重启IIS服务iisreset命令否则更改不生效。这是新手最容易忽略的步骤——改完MIME表浏览器还是下载第一反应是“IIS坏了”其实是忘了重启。更深层的原理是MIME类型不仅影响浏览器行为还影响CDN缓存策略。如果IIS返回application/octet-streamCDN会把它当二进制文件缓存而audio/flac则可能触发专门的音视频缓存规则如边缘节点预加载前1MB。虽然本项目不用CDN但理解这点能帮你预判未来扩展时的瓶颈。3.2 文件头Header决定播放起点为什么你的MP4总要缓冲5秒你有没有遇到这种情况同一个MP4文件在VLC里秒开在浏览器里却要等5秒才出画面问题大概率出在文件的moov原子位置。MP4文件结构像一本书ftyp封面、moov目录、mdat正文。浏览器播放器需要先读取moov才能知道视频有多长、有多少轨道、关键帧在哪。如果moov被放在文件末尾FFmpeg默认行为浏览器就得把整个200MB文件下载完才能开始播放——这就是“缓冲5秒”的真相。解决方法用FFmpeg重写文件头把moov挪到开头ffmpeg -i input.mp4 -c copy -movflags faststart output.mp4参数解读-c copy不重新编码只拷贝流速度极快10GB文件30秒内完成-movflags faststart强制moov置于文件开头。实测对比同一台Win10机器IIS 10服务文件状态首帧时间网络流量首帧前未优化moov在末尾4.7秒192MB几乎全文件已优化moov在开头0.8秒12KB仅moov box这个优化不需要改IIS配置但它是让IIS真正“胜任”视频服务的基础。我建议所有准备上传的MP4都走一遍这个命令。可以写个批处理脚本放到media\video\目录下双击自动优化整个文件夹echo off for %%i in (*.mp4) do ( echo 正在优化 %%i... ffmpeg -i %%i -c copy -movflags faststart optimized_%%i del %%i ren optimized_%%i %%i ) pause3.3 播放器兼容性别迷信“HTML5支持表”要看真实设备表现W3C官网的HTML5音视频支持表列得很漂亮“Chrome支持MP4、WebM、Ogg”。但真实世界远比表格复杂。我们测试了5类常见终端终端类型MP4 (H.264AAC)WebM (VP9Opus)FLAC备注Win10 Chrome 115✅ 完美✅ 完美✅默认首选Win10 Edge 115✅ 完美✅ 完美✅同Chromium内核iPadOS 16 Safari✅ 完美❌ 不支持VP9✅Safari 16.4才支持FLACAndroid 12 Chrome✅ 完美✅ 完美❌ 下载Android Chrome不解析audio/flac老年机Win7 IE11✅需Flash fallback❌❌IE11已停止支持但仍有存量关键发现FLAC在移动端支持度远低于桌面端。Android Chrome明确不支持audio srcsong.flac点开会直接触发下载。解决方案不是放弃FLAC而是用JavaScript做运行时检测function canPlayFlac() { const a document.createElement(audio); return !!(a.canPlayType a.canPlayType(audio/flac).replace(/no/, )); } if (canPlayFlac()) { // 加载FLAC文件 player.src media/audio/song.flac; } else { // 降级到MP3 player.src media/audio/song.mp3; }这段代码在页面加载时执行自动选择当前设备支持的最佳格式。它比“统一转MP3”更尊重原始音质也比“强制用WebAssembly解码FLAC”更轻量后者需额外加载1MB JS库。另一个易踩坑点是自动播放策略。Chrome 66禁止无用户交互的自动播放防止骚扰广告。所以video autoplay在大多数情况下会静音且暂停。正确做法是用video muted autoplay并在用户第一次点击页面任意位置后再调用play()解除静音let isUserInteracted false; document.addEventListener(click, () { isUserInteracted true; }, { once: true }); // 用户点击后尝试播放并取消静音 if (isUserInteracted video.muted) { video.muted false; video.play().catch(e console.log(自动取消静音失败:, e)); }这个细节决定了你的迎新视频站是“点开就动”还是“用户得先点一下屏幕才能看”。4. 实操全流程从启用IIS到上线可播放的音乐视频站4.1 环境准备Win10专业版启用IIS的5个必做动作IIS在Win10中是“可选功能”默认关闭。启用过程看似简单但有5个隐藏陷阱必须避开动作1启用IIS核心服务非“万能勾选”路径设置 → 应用 → 可选功能 → 添加功能 → “Internet Information Services”⚠️ 错误做法勾选整个IIS节点包含FTP、SMTP等无关服务✅ 正确勾选仅以下4项☑ Internet Information Services☑ Web管理工具 → IIS管理控制台☑ World Wide Web服务 → 常见HTTP功能 → 静态内容、默认文档、目录浏览☑ World Wide Web服务 → 性能功能 → 静态内容压缩理由勾选“目录浏览”是为了开发期快速验证文件是否上传成功禁用“动态内容”ASP.NET、CGI是为了安全避免无意中暴露脚本执行入口。动作2关闭Windows防火墙的HTTP端口拦截Win10防火墙默认阻止80端口入站。即使IIS启动了外网也访问不了。操作控制面板 → Windows Defender防火墙 → 高级设置 → 入站规则 → 新建规则 → 端口 → TCP 80 → 允许连接 → 命名为“IIS-HTTP”动作3设置网站物理路径的NTFS权限IIS工作进程IIS AppPool\DefaultAppPool需要读取D:\MusicSite\的权限。右键文件夹 → 属性 → 安全 → 编辑 → 添加 → 输入IIS AppPool\DefaultAppPool→ 勾选“读取执行”、“列出文件夹内容”、“读取”。⚠️ 常见错误只给Users组权限但IIS进程不以Users身份运行。动作4配置默认文档避免403错误IIS默认只认default.htm、index.html等5个文件名。如果你的首页叫home.html访问http://localhost会报403 Forbidden。操作IIS管理器 → 网站节点 → “默认文档” → 右侧“添加” → 输入index.html→ 上移到第一位。动作5启用“静态内容”功能常被忽略即使勾选了IISWin10仍可能禁用静态内容模块。检查方法在浏览器访问http://localhost/test.txt如果返回404而非文件内容说明此模块未启用。启用PowerShell管理员执行Enable-WindowsOptionalFeature -Online -FeatureName IIS-StaticContent -NoRestart完成这5步打开http://localhost你应该看到IIS默认欢迎页。此时IIS服务已具备承载音视频网站的全部基础能力。4.2 网站创建与配置3分钟完成一个可访问的虚拟目录假设你的音视频文件已整理好放在D:\MusicSite\。现在要把它变成可通过网络访问的网站步骤1添加网站IIS管理器 → 左侧连接树 → 右键“网站” → “添加网站”网站名称MusicVideoSite物理路径D:\MusicSite\绑定类型httpIP地址全部未分配端口80主机名留空即http://localhost或http://192.168.1.100步骤2配置MIME类型关键网站节点 → 双击“MIME类型” → 右侧“添加” → 按3.1节表格逐一添加.wav、.flac等类型。步骤3启用目录浏览仅开发期网站节点 → 双击“目录浏览” → 右侧“启用”。此时访问http://localhost/media/audio/能看到所有MP3文件列表方便快速验证文件是否被IIS识别。步骤4设置匿名认证让访客无需登录网站节点 → 双击“身份验证” → 右键“匿名身份验证” → “启用”右键“Windows身份验证” → “禁用”。理由我们的目标是“打开即用”不是企业内网单点登录。步骤5测试基础访问在服务器本机浏览器访问http://localhost/index.html应看到你的首页在局域网另一台电脑访问http://192.168.1.100/index.html也应正常显示。如果后者失败回头检查防火墙规则和IP绑定。实操心得我曾帮某社区中心部署时卡在“局域网无法访问”。排查3小时后发现他们的路由器启用了“AP隔离”功能禁止同一WiFi下的设备互访。解决方案不是改IIS而是关掉路由器的AP隔离。所以当IIS配置确认无误却无法访问时先查网络设备再查服务器。4.3 播放器页面开发150行HTMLCSSJS实现专业级体验下面是一个精简但功能完整的index.html骨架已通过Chrome、Edge、Safari实测!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title我的音乐视频站/title style :root { --primary: #4a6fa5; } body { font-family: Segoe UI, sans-serif; margin: 0; padding: 20px; background: #f5f7fa; } .player { background: white; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); padding: 20px; max-width: 800px; margin: 0 auto; } .cover { width: 100%; height: 200px; background: linear-gradient(135deg, var(--primary), #6b8cbc); border-radius: 6px; margin-bottom: 15px; display: flex; align-items: center; justify-content: center; color: white; font-size: 18px; } .controls { display: flex; align-items: center; margin: 15px 0; } .btn { background: var(--primary); color: white; border: none; padding: 8px 16px; border-radius: 4px; cursor: pointer; margin-right: 10px; } .progress-container { flex: 1; height: 6px; background: #e0e0e0; border-radius: 3px; position: relative; } .progress-bar { height: 100%; background: var(--primary); border-radius: 3px; width: 0%; } .time-info { font-size: 14px; color: #666; margin-top: 5px; display: flex; justify-content: space-between; } .playlist { margin-top: 30px; } .track { padding: 12px; border-bottom: 1px solid #eee; cursor: pointer; } .track:hover { background: #f0f4f8; } .track.active { background: #e6f0ff; } .track-info { display: flex; align-items: center; } .track-number { width: 30px; color: #888; } .track-title { flex: 1; font-weight: 500; } .track-duration { width: 60px; text-align: right; color: #888; } /style /head body div classplayer div classcover idcover点击播放一首歌/div div classcontrols button classbtn idprevBtn⏮/button button classbtn idplayBtn▶/button button classbtn idpauseBtn⏸/button button classbtn idnextBtn⏭/button /div div classprogress-container div classprogress-bar idprogressBar/div /div div classtime-info span idcurrentTime0:00/span span idduration0:00/span /div div classplaylist idplaylist/div /div script // 播放器核心逻辑 const audio new Audio(); let currentTrackIndex 0; const tracks [ { title: 春日序曲, file: media/audio/spring.flac, duration: 3:42, cover: assets/images/spring.jpg }, { title: 雨夜钢琴, file: media/audio/rain.mp3, duration: 4:15, cover: assets/images/rain.jpg } ]; // 初始化播放列表 function initPlaylist() { const playlistEl document.getElementById(playlist); tracks.forEach((track, index) { const div document.createElement(div); div.className track; div.innerHTML div classtrack-info div classtrack-number${index 1}./div div classtrack-title${track.title}/div div classtrack-duration${track.duration}/div /div ; div.addEventListener(click, () playTrack(index)); playlistEl.appendChild(div); }); } // 播放指定曲目 function playTrack(index) { if (index 0 || index tracks.length) return; currentTrackIndex index; const track tracks[index]; // 更新封面 document.getElementById(cover).style.backgroundImage url(${track.cover}); document.getElementById(cover).textContent track.title; // 设置音频源自动选择格式 const src getBestAudioSource(track.file); audio.src src; audio.load(); // 触发元数据加载 audio.play().catch(e console.log(播放失败:, e)); } // 根据设备支持度选择最佳格式 function getBestAudioSource(basePath) { if (canPlayFlac() basePath.endsWith(.flac)) { return basePath; } else if (basePath.endsWith(.flac)) { return basePath.replace(.flac, .mp3); } return basePath; } // 播放控制按钮绑定 document.getElementById(playBtn).onclick () audio.play(); document.getElementById(pauseBtn).onclick () audio.pause(); document.getElementById(prevBtn).onclick () playTrack(currentTrackIndex - 1); document.getElementById(nextBtn).onclick () playTrack(currentTrackIndex 1); // 进度条拖拽 const progressBar document.getElementById(progressBar); const progressContainer progressBar.parentElement; progressContainer.addEventListener(click, (e) { const width progressContainer.clientWidth; const clickX e.offsetX; audio.currentTime (clickX / width) * audio.duration; }); // 时间更新 audio.addEventListener(timeupdate, () { const percent (audio.currentTime / audio.duration) * 100; progressBar.style.width ${percent}%; document.getElementById(currentTime).textContent formatTime(audio.currentTime); }); audio.addEventListener(loadedmetadata, () { document.getElementById(duration).textContent formatTime(audio.duration); }); // 格式化时间秒→分:秒 function formatTime(seconds) { const mins Math.floor(seconds / 60); const secs Math.floor(seconds % 60); return ${mins}:${secs 10 ? 0 : }${secs}; } // 兼容性检测 function canPlayFlac() { const a document.createElement(audio); return !!(a.canPlayType a.canPlayType(audio/flac).replace(/no/, )); } // 页面加载完成后初始化 window.onload () { initPlaylist(); playTrack(0); // 自动播放第一首 }; /script /body /html这个页面的亮点在于无框架依赖纯原生JS不引入任何外部库智能格式降级自动检测FLAC支持不支持时无缝切换到MP3进度条精准拖拽基于offsetX计算不受父容器padding影响响应式设计在手机上也能清晰看到曲目列表和控制按钮。将此代码保存为D:\MusicSite\index.html刷新浏览器你就能看到一个可立即使用的音乐播放器。后续只需修改tracks数组就能增删曲目——这才是内容创作者真正需要的“所见即所得”。4.4 高级技巧用URL参数实现“一键分享指定视频”很多用户问“能不能发一个链接让朋友点开就直接播放第三首歌”答案是肯定的而且不需要后端。利用HTML5的URLSearchParamsAPI我们可以实现纯前端的参数解析在index.html的script末尾添加// 解析URL参数?track2 const urlParams new URLSearchParams(window.location.search); const startTrack parseInt(urlParams.get(track)) || 0; if (startTrack 0 startTrack tracks.length) { window.onload () playTrack(startTrack - 1); }然后分享链接就变成http://192.168.1.100/?track3→ 自动播放第三首http://192.168.1.100/?track1→ 自动播放第一首这个技巧被某高校音乐系广泛使用老师把期末考试录像上传后给每位学生发一个带?track学号的链接学生点开就只看到自己的演奏视频隐私和效率兼得。5. 常见问题与独家避坑指南那些文档里不会写的实战经验5.1 问题速查表从404到黑屏的12个高频故障现象可能原因排查命令/操作解决方案访问http://localhost显示404IIS服务未启动Get-Service W3SVC | Select StatusPowerShellStart-Service W3SVCMP3能播WAV点开下载MIME类型未添加IIS管理器 → 服务器节点 → MIME类型 → 查找.wav添加audio/wav重启IIS视频播放卡顿进度条不动moov原子在文件末尾ffprobe -v quiet -show_entries formatduration input.mp4用ffmpeg -i input.mp4 -c copy -movflags faststart output.mp4重写局域网其他电脑无法访问Windows防火墙拦截netsh advfirewall firewall show rule nameIIS-HTTP确保规则状态为“启用”播放器显示“InvalidStateError”音频未加载完成就调play()浏览器开发者工具 → Console标签改用audio.load(); audio.addEventListener(loadeddata, () audio.play());封面图不显示显示空白灰块图片路径错误或跨域浏览器F12 → Network标签 → 点击图片请求检查src路径是否相对于index.html如assets/images/cover.jpg移动端点击播放无反应自动播放策略阻止iOS Safari控制台输入navigator.userAgent必须有用户手势click/touch后才能调play()播放时声音忽大忽小音频文件音量不一致用Audacity打开多个文件 → 分析 → 响度标准化批量处理ffmpeg -i input.mp3 -af loudnormI-16:LRA11:TP-1.5 output.mp3JSON数据不加载控制台报错JSON格式非法多逗号、单引号用https://jsonlint.com/验证songs.json严格使用双引号末尾不加逗号页面中文乱码显示HTML未声明UTF-

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑