You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Alpine.js+Tailwind音频流在现代浏览器播放报错修复

问题原因
  • audio.play() 是异步方法,返回Promise对象,原代码未处理异步状态,播放请求还在初始化阶段就触发暂停,就会抛出Uncaught (in promise) DOMException: The play() request was interrupted by a call to pause()错误
  • 站点部署在HTTPS协议下,但音频流地址用的是HTTP协议,现代浏览器默认拦截HTTPS页面中的HTTP非安全资源(混合内容规则),直接导致音频资源加载失败
  • audio标签添加了不必要的autoplay属性,现代浏览器默认禁止无用户交互的自动播放,页面初始化时就尝试触发播放会直接被拦截报错
  • 错误给Tab键绑定了播放/停止事件,Tab键默认功能是切换页面焦点,用户按Tab导航时会意外触发播放逻辑,和点击事件冲突导致播放频繁中断
  • 直播流是无固定时长的流式资源,原代码暂停时执行currentTime = 0会强制重新发起流连接,极易触发加载中断
修正后代码

HTML部分

<!-- 播放/停止按钮组件 -->
<div x-data="playaudio()" x-init="init" class="grid place-content-center m-14">
  <button 
    @click="playAndStop" 
    @keydown.enter.prevent="playAndStop"
    @keydown.space.prevent="playAndStop"
    type="button"
    aria-label="播放/停止音频流"
    class="relative rounded-xl group cursor-pointer focus:outline-none focus:ring focus:ring-[#1F89AE]"
  >
    <div class="absolute inset-0 flex items-center justify-center p-8">
      <div class="w-full h-full transition duration-300 ease-in-out bg-cyan-500 filter group-hover:blur-2xl"></div>
    </div>
    <div class="absolute inset-0 flex items-center justify-center transition duration-200 ease-in-out bg-black rounded-xl bg-opacity-30 group-hover:bg-opacity-20">
      <!-- 播放图标 -->
      <div x-show="!currentlyPlaying" class="bg-black bg-opacity-50 rounded-full p-0.5">
        <svg
          class="w-20 h-20 text-white text-opacity-0 transition duration-150 ease-in-out hover:text-opacity-20"
          viewBox="0 0 284 284" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
          <path d="M184.197 129.243L135.177 96.5521C132.865 95.01 130.178 94.1249 127.403 93.9915C124.628 93.8581 121.868 94.4813 119.419 95.7946C116.971 97.1079 114.925 99.0619 113.501 101.448C112.077 103.834 111.327 106.562 111.333 109.34V174.706C111.333 177.482 112.086 180.206 113.513 182.588C114.939 184.969 116.985 186.919 119.433 188.228C121.881 189.538 124.638 190.158 127.411 190.024C130.183 189.889 132.867 189.004 135.177 187.463L184.197 154.773C186.297 153.373 188.019 151.475 189.21 149.25C190.401 147.025 191.024 144.54 191.024 142.015C191.024 139.491 190.401 137.006 189.21 134.781C188.019 132.555 186.297 130.658 184.197 129.258V129.243Z" fill="white"></path>
          <path d="M280 142C280 160.122 276.431 178.067 269.495 194.81C262.56 211.553 252.395 226.766 239.581 239.581C226.766 252.395 211.553 262.56 194.81 269.495C178.067 276.431 160.122 280 142 280C123.878 280 105.933 276.431 89.1897 269.495C72.4468 262.56 57.2337 252.395 44.4193 239.581C31.6048 226.766 21.4398 211.553 14.5046 194.81C7.56947 178.067 4 160.122 4 142C4 105.4 18.5392 70.2993 44.4193 44.4193C70.2993 18.5392 105.4 4 142 4C178.6 4 213.701 18.5392 239.581 44.4193C265.461 70.2993 280 105.4 280 142Z" stroke="white" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"></path>
        </svg>
      </div>
      <!-- 停止图标 -->
      <div x-show="currentlyPlaying" class="bg-black bg-opacity-50 rounded-full p-0.5">
        <svg xmlns="http://www.w3.org/2000/svg"
          class="w-20 h-20 text-white text-opacity-0 transition duration-150 ease-in-out hover:text-opacity-20"
          viewBox="0 0 20 20" fill="white">
          <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8 7a1 1 0 00-1 1v4a1 1 0 001 1h4a1 1 0 001-1V8a1 1 0 00-1-1H8z" clip-rule="evenodd" />
        </svg>
      </div>
    </div>
  </button>
  <!-- 移除无效autoplay属性,必须将src替换为HTTPS协议的音频流地址 -->
  <audio x-ref="audio" preload="none">
    <source src="替换为HTTPS协议的MP3流地址" type="audio/mpeg" />
  </audio>
</div>

JS逻辑部分

function playaudio() {
  return {
    currentlyPlaying: false,
    isLoading: false,
    async playAndStop() {
      const audio = this.$refs.audio;
      // 加载过程中禁止重复触发操作
      if (this.isLoading) return;

      if (this.currentlyPlaying) {
        audio.pause();
        this.currentlyPlaying = false;
        return;
      }

      try {
        this.isLoading = true;
        // 等待播放请求完成,避免中断报错
        await audio.play();
        this.currentlyPlaying = true;
      } catch (err) {
        console.error('音频播放失败:', err);
        this.currentlyPlaying = false;
      } finally {
        this.isLoading = false;
      }
    },
    init() {
      const audio = this.$refs.audio;
      // 同步音频原生事件状态,避免UI和实际播放状态不一致
      audio.addEventListener('error', () => {
        this.currentlyPlaying = false;
        this.isLoading = false;
      });
      audio.addEventListener('stalled', () => {
        this.isLoading = true;
      });
      audio.addEventListener('playing', () => {
        this.isLoading = false;
        this.currentlyPlaying = true;
      });
    }
  }
}
部署注意事项
  • 必须将音频流地址替换为HTTPS协议地址,否则浏览器会直接拦截资源请求,代码逻辑正确也无法播放。如果现有流服务不支持HTTPS,可以通过反向代理给流端口配置SSL证书
  • 移除了错误的Tab键事件绑定,仅保留回车、空格触发播放的逻辑,符合网页无障碍规范,不会干扰用户正常的焦点导航操作
  • 去掉了暂停时重置currentTime的逻辑,直播流没有固定进度点,强制重置会触发不必要的重连,反而容易导致播放失败
  • 新增加载锁,避免用户快速点击按钮时重复触发播放/暂停请求

内容的提问来源于stack exchange,提问作者MOH SUBHAN

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 13:01:01