C# UnityWebRequest在调用Bing语音API时返回HTTP状态408

C# UnityWebRequest在调用Bing语音API时返回HTTP状态408,c#,unity3d,webrequest,microsoft-cognitive,http-error,C#,Unity3d,Webrequest,Microsoft Cognitive,Http Error,我正在尝试调用Unity3D中的Microsoft Bing文本到语音API using System.Collections; using System.Xml.Linq; using UnityEngine; using UnityEngine.Networking; public class TextToSpeech : MonoBehaviour { public AudioSource audioSource; public static readonly strin

我正在尝试调用Unity3D中的Microsoft Bing文本到语音API

using System.Collections;
using System.Xml.Linq;
using UnityEngine;
using UnityEngine.Networking;

public class TextToSpeech : MonoBehaviour
{
    public AudioSource audioSource;
    public static readonly string accessUri = "https://api.cognitive.microsoft.com/sts/v1.0/issueToken";
    public static readonly string synthesizeUri = "https://speech.platform.bing.com/synthesize";
    public string textToSpeak = "Oh yeah! Finally Dorot is speaking.";
    private static string accessToken;
    private static readonly string apiKey = "MY API KEY";
    private string postStringData;

    public TextToSpeech (string textToSpeak)
    {
        this.textToSpeak = textToSpeak;
    }

    public void Speak()
    {
        audioSource = gameObject.GetComponent<AudioSource>();
        StartCoroutine(RequestToken(apiKey));
    }

    private string GenerateSsml(string textToSpeak)
    {
        var ssmlDoc = new XDocument(
                          new XElement("speak",
                              new XAttribute("version", "1.0"),
                              new XAttribute(XNamespace.Xml + "lang", "en-US"),
                              new XElement("voice",
                                  new XAttribute(XNamespace.Xml + "lang", "en-US"),
                                  new XAttribute(XNamespace.Xml + "gender", "Male"),
                                  new XAttribute("name", "Microsoft Server Speech Text to Speech Voice (en-US, BenjaminRUS)"),
                                  textToSpeak)));
        return ssmlDoc.ToString();
    }

    public IEnumerator RequestToken(string apiKey)
    {
        var tokenRequest = UnityWebRequest.Post(accessUri, "data");
        tokenRequest.SetRequestHeader("Ocp-Apim-Subscription-Key", apiKey);

        var tokenResponse = tokenRequest.SendWebRequest();
        yield return tokenResponse;

        if (tokenRequest.isHttpError)
        {
            Debug.LogError("HTTP Error: " + tokenRequest.error + " Code: " + tokenRequest.responseCode);
        }
        else
        {
            postStringData = GenerateSsml(textToSpeak);
            accessToken = tokenRequest.downloadHandler.text;
            Debug.Log("Access token: " + accessToken);

            StartCoroutine(Synthesize(postStringData, accessToken));
        }
    }

    public IEnumerator Synthesize(string text, string token)
    {
        var synReq = UnityWebRequest.Post(synthesizeUri, text);
        synReq.SetRequestHeader("Content-Type", "application/ssml+xml");
        synReq.SetRequestHeader("X-Microsoft-OutputFormat", "riff-16khz-16bit-mono-pcm");
        synReq.SetRequestHeader("X-Search-AppId", "07D3234E49CE426DAA29772419F436CA");
        synReq.SetRequestHeader("X-Search-ClientID", "1ECFAE91408841A480F00935DC390960");
        synReq.SetRequestHeader("User-Agent", "Dorot");
        synReq.SetRequestHeader("Authorization", "Bearer " + token);

        var synRes = synReq.SendWebRequest();
        yield return synRes;

        if (synReq.isHttpError)
        {
            Debug.LogError("HTTP Error: " + synReq.error + " Code: " + synReq.responseCode + " isNetworkError: " + synReq.isNetworkError + " isDone: " + synReq.isDone);
        }
        else
        {
            AudioClip cc = DownloadHandlerAudioClip.GetContent(synReq);
            audioSource.clip = cc;
            audioSource.Play();
        }
    }
}
此API需要一个accessToken和将在请求头中传递的其他参数。 首先,为了获得accessToken,我向令牌API发送了一个POST请求,之后,我在请求头中发送了其他参数,它在Postman中工作得非常好(返回Wav音频剪辑),如下所示:

为了在Unity中实现这一点,我使用了UnityWebRequest类来发送两个POST请求(顺序),然后接收音频响应

using System.Collections;
using System.Xml.Linq;
using UnityEngine;
using UnityEngine.Networking;

public class TextToSpeech : MonoBehaviour
{
    public AudioSource audioSource;
    public static readonly string accessUri = "https://api.cognitive.microsoft.com/sts/v1.0/issueToken";
    public static readonly string synthesizeUri = "https://speech.platform.bing.com/synthesize";
    public string textToSpeak = "Oh yeah! Finally Dorot is speaking.";
    private static string accessToken;
    private static readonly string apiKey = "MY API KEY";
    private string postStringData;

    public TextToSpeech (string textToSpeak)
    {
        this.textToSpeak = textToSpeak;
    }

    public void Speak()
    {
        audioSource = gameObject.GetComponent<AudioSource>();
        StartCoroutine(RequestToken(apiKey));
    }

    private string GenerateSsml(string textToSpeak)
    {
        var ssmlDoc = new XDocument(
                          new XElement("speak",
                              new XAttribute("version", "1.0"),
                              new XAttribute(XNamespace.Xml + "lang", "en-US"),
                              new XElement("voice",
                                  new XAttribute(XNamespace.Xml + "lang", "en-US"),
                                  new XAttribute(XNamespace.Xml + "gender", "Male"),
                                  new XAttribute("name", "Microsoft Server Speech Text to Speech Voice (en-US, BenjaminRUS)"),
                                  textToSpeak)));
        return ssmlDoc.ToString();
    }

    public IEnumerator RequestToken(string apiKey)
    {
        var tokenRequest = UnityWebRequest.Post(accessUri, "data");
        tokenRequest.SetRequestHeader("Ocp-Apim-Subscription-Key", apiKey);

        var tokenResponse = tokenRequest.SendWebRequest();
        yield return tokenResponse;

        if (tokenRequest.isHttpError)
        {
            Debug.LogError("HTTP Error: " + tokenRequest.error + " Code: " + tokenRequest.responseCode);
        }
        else
        {
            postStringData = GenerateSsml(textToSpeak);
            accessToken = tokenRequest.downloadHandler.text;
            Debug.Log("Access token: " + accessToken);

            StartCoroutine(Synthesize(postStringData, accessToken));
        }
    }

    public IEnumerator Synthesize(string text, string token)
    {
        var synReq = UnityWebRequest.Post(synthesizeUri, text);
        synReq.SetRequestHeader("Content-Type", "application/ssml+xml");
        synReq.SetRequestHeader("X-Microsoft-OutputFormat", "riff-16khz-16bit-mono-pcm");
        synReq.SetRequestHeader("X-Search-AppId", "07D3234E49CE426DAA29772419F436CA");
        synReq.SetRequestHeader("X-Search-ClientID", "1ECFAE91408841A480F00935DC390960");
        synReq.SetRequestHeader("User-Agent", "Dorot");
        synReq.SetRequestHeader("Authorization", "Bearer " + token);

        var synRes = synReq.SendWebRequest();
        yield return synRes;

        if (synReq.isHttpError)
        {
            Debug.LogError("HTTP Error: " + synReq.error + " Code: " + synReq.responseCode + " isNetworkError: " + synReq.isNetworkError + " isDone: " + synReq.isDone);
        }
        else
        {
            AudioClip cc = DownloadHandlerAudioClip.GetContent(synReq);
            audioSource.clip = cc;
            audioSource.Play();
        }
    }
}
使用系统集合;
使用System.Xml.Linq;
使用UnityEngine;
使用UnityEngine。联网;
公共类TextToSpeech:monobhavior
{
公共音频源;
公共静态只读字符串accessUri=”https://api.cognitive.microsoft.com/sts/v1.0/issueToken";
公共静态只读字符串合成器URI=”https://speech.platform.bing.com/synthesize";
公共字符串textToSpeak=“哦,是的!多罗终于开口了。”;
私有静态字符串accessToken;
私有静态只读字符串apiKey=“MY API KEY”;
私有字符串postStringData;
公共TextToSpeech(字符串textToSpeak)
{
this.textToSpeak=textToSpeak;
}
公开演讲
{
audioSource=gameObject.GetComponent

如何解决此问题?谢谢。

找到了解决方案

根据回答,
UnityWebRequest
默认情况下将
chunkedTransfer
设置为
true
。因此您需要执行以下操作:

synReq.chunkedTransfer = false;

顺便说一句:您可以按照以下指南编写单元测试:(这是我尝试的)

您还需要“synthesis”中的
Ocp-Apim订阅密钥
头吗请求?@Jon不,令牌替换了api密钥。OP,你能在Github中发布一个可复制的示例吗?我看你的代码没问题,但我不知道Unity,所以无法运行它。@Jon,子订阅密钥只是用来获取访问令牌,访问令牌将在头中发送(授权)@marainesparnisari,这是一个.NETCore示例,来自GitHub:和另一个Node.js示例: