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

前端页面(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. 输入参数并合成语音

相关推荐
合作小小程序员小小店1 天前
web网页开发,在线%考试管理%系统,基于Idea,vscode,html,css,vue,java,maven,springboot,mysql
java·前端·系统架构·vue·intellij-idea·springboot
天天进步20151 天前
CSS Grid与Flexbox:2025年响应式布局终极指南
前端·css
Boop_wu1 天前
[Java EE] 计算机基础
java·服务器·前端
Novlan11 天前
TDesign UniApp 组件库来了
前端
用户47949283569151 天前
React DevTools 组件名乱码?揭秘从开发到生产的代码变形记
前端·react.js
顾安r1 天前
11.8 脚本网页 打砖块max
服务器·前端·html·css3
倚栏听风雨1 天前
typescript 方法前面加* 是什么意思
前端
狮子不白1 天前
C#WEB 防重复提交控制
开发语言·前端·程序人生·c#
菜鸟‍1 天前
【前端学习】阿里前端面试题
前端·javascript·学习
Jonathan Star1 天前
LangFlow前端源码深度解析:核心模块与关键实现
前端