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

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

相关推荐
haogexiaole38 分钟前
vue知识点总结
前端·javascript·vue.js
哆啦A梦15883 小时前
[前台小程序] 01 项目初始化
前端·vue.js·uni-app
小周同学@5 小时前
谈谈对this的理解
开发语言·前端·javascript
Wiktok5 小时前
Pyside6加载本地html文件并实现与Javascript进行通信
前端·javascript·html·pyside6
一只小风华~5 小时前
Vue:条件渲染 (Conditional Rendering)
前端·javascript·vue.js·typescript·前端框架
柯南二号5 小时前
【大前端】前端生成二维码
前端·二维码
程序员码歌6 小时前
明年35岁了,如何破局?说说心里话
android·前端·后端
博客zhu虎康7 小时前
React Hooks 报错?一招解决useState问题
前端·javascript·react.js
灰海7 小时前
vue中通过heatmap.js实现热力图(多个热力点)热区展示(带鼠标移入弹窗)
前端·javascript·vue.js·heatmap·heatmapjs
王源骏7 小时前
LayaAir鼠标(手指)控制相机旋转,限制角度
前端