前端调用阿里云接口语音合成演示

前端页面(html)

javascript 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>阿里云语音合成演示</title>
    <style>
        /* 样式代码保持不变(见原始代码) */
    </style>
</head>
<body>
    <div class="container">
        <!-- 页面结构保持不变(见原始代码) -->
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', () => {
            const synthesizeBtn = document.getElementById('synthesize');
            const audioPlayer = document.getElementById('audioPlayer');
            const statusDiv = document.getElementById('status');

            synthesizeBtn.addEventListener('click', async () => {
                // 获取输入参数
                const params = {
                    appkey: document.getElementById('appkey').value.trim(),
                    token: document.getElementById('token').value.trim(),
                    text: document.getElementById('text').value.trim(),
                    voice: document.getElementById('voice').value,
                    volume: document.getElementById('volume').value,
                    speed: document.getElementById('speed').value
                };

                // 参数验证逻辑...

                synthesizeBtn.disabled = true;
                showStatus('正在合成语音,请稍候...', 'info');

                try {
                    // 调用代理服务
                    const audioData = await fetchAudio(params);
                    const audioBlob = new Blob([audioData], { type: 'audio/wav' });
                    audioPlayer.src = URL.createObjectURL(audioBlob);
                    showStatus('语音合成成功!', 'success');
                } catch (error) {
                    showStatus(`语音合成失败: ${error.message}`, 'error');
                } finally {
                    synthesizeBtn.disabled = false;
                }
            });

            async function fetchAudio(params) {
                // 构造代理请求URL
                const proxyUrl = 'http://localhost:3000/tts-proxy';
                const query = new URLSearchParams({
                    ...params,
                    text: params.text // 自动编码
                }).toString();
                
                const response = await fetch(`${proxyUrl}?${query}`);
                
                if (!response.ok) {
                    const errorText = await response.text();
                    throw new Error(`请求失败: ${response.status} ${errorText}`);
                }
                
                return await response.arrayBuffer();
            }

            function showStatus(message, type) {
                /* 状态显示逻辑 */
            }
        });
    </script>
</body>
</html>

前端直接调用阿里云语音合成API时,通常会遇到跨域请求限制(CORS)。浏览器出于安全考虑会阻止这类跨域请求。

解决方案

搭建Node.js代理服务器作为前端和阿里云API之间的中转层,解决跨域问题。以下是完整实现:

代理服务器实现(Node.js)
javascript 复制代码
const express = require("express");
const axios = require("axios");
const app = express();

// 请求日志中间件
app.use((req, res, next) => {
  console.log(`${new Date().toLocaleString()} - ${req.method} ${req.url}`);
  next();
});

// 处理预检请求
app.options("/tts-proxy", (req, res) => {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
  res.header("Access-Control-Allow-Headers", "Content-Type, Authorization, Content-Length, X-Requested-With");
  res.sendStatus(204);
});

// 语音合成代理接口
app.get("/tts-proxy", async (req, res) => {
  res.header("Access-Control-Allow-Origin", "*");
  
  try {
    const { appkey, token, text, voice, volume, speed } = req.query;
    const apiUrl = `https://nls-gateway-cn-shanghai.aliyuncs.com/stream/v1/tts?appkey=${appkey}&token=${token}&text=${encodeURIComponent(text)}&voice=${voice}&volume=${volume}&speech_rate=${speed}&format=wav`;
    
    const response = await axios({
      method: "post",
      url: apiUrl,
      responseType: "arraybuffer",
    });

    res.set("Content-Type", "audio/wav");
    res.send(response.data);
  } catch (error) {
    console.error("代理错误:", error);
    
    if (error.response) {
      console.error("阿里云错误状态:", error.response.status);
      console.error("阿里云错误数据:", error.response.data.toString());
    }

    res.status(500).json({
      error: "语音合成失败",
      details: error.message,
    });
  }
});

// 启动服务
const PORT = 3000;
app.listen(PORT, () => {
  console.log(`代理服务运行在 http://localhost:${PORT}`);
});

实现原理

  1. 跨域处理:

    • 代理服务器设置CORS响应头(Access-Control-Allow-Origin: *)
    • 处理OPTIONS预检请求
  2. 请求转发:

  3. 错误处理:

    • 捕获代理服务和阿里云API的错误
    • 返回详细错误信息给前端

使用步骤

  1. 安装依赖:

    javascript 复制代码
    npm install express axios
  2. 启动代理服务:

    javascript 复制代码
    node server.js
  3. 访问前端页面:

    javascript 复制代码
    http://localhost:3000/index.html
  4. 输入参数并合成语音

相关推荐
子兮曰37 分钟前
把 649 种文件格式塞进一个网页里:一个「文件不出浏览器」的预览器
前端·javascript·后端
sm_926787054 小时前
RFID 标签打印的技术实现要点与二次开发实践
java·大数据·前端·c++·编辑器
IMPYLH4 小时前
HTML 的 <video> 元素
前端·html
溪语流沙5 小时前
【每天一个CSS | Day19】流光文字与一笔写成的手写签名
前端·javascript·css
逐光者9335 小时前
STM32——SPI 屏 · Flash · 高速
java·前端·stm32
To_OC5 小时前
同样是让 AI 写全栈,为什么别人一句话就够了
前端·前端框架·next.js
CDwenhuohuo5 小时前
electron pc项目打包成桌面端
前端·javascript·electron
前端大斗师5 小时前
「大于 1000」把 1000 元那单也算进去了:我在 Vue3 订单页对了 10 句话
前端·人工智能·typescript·大模型·原力计划
Jmyd01236 小时前
用 Web VR 引擎搭建 3D 虚拟展厅:从素材上云到多端实时渲染的完整数据链路
前端·3d·vr·三维数字化
刘天远6 小时前
Agent成本核算实现:事件表、状态分布与Python归集
前端·数据库·人工智能·python