admin管理员组

文章数量:1626405

今天给客户写了一个语音提示的小程序,在XP系统上测试发现请求百度的TTS语音失败,最开始抛出来的异常是“基础连接已经关闭: 发送时发生错误”,在网上找了一些解决方案,其中包括添加以下代码片段

ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;

结果又出现了“不支持请求的安全协议”,最后就想找一个第三方的https请求模块,放弃C#的WebRequest,最后找到了BouncyCastle.Crypto,可以直接在NuGet中搜索安装即可,但是用它来请求,就需要自己来解析响应的结果,这里稍微麻烦了点

 private void Download(string text)
        {
            
            
            TlsClientProtocol protocol = null;
            try
            {
                string host = "fanyi.baidu";
                int port = 443;
                string request = string.Format("GET /gettts?lan=zh&text={0}&spd=5&source=web HTTP/1.1\r\nHost: {1}\r\n\r\n", text, host);
                TcpClient tcpClient = new TcpClient(host, port);                
                protocol = new TlsClientProtocol(tcpClient.GetStream(), new Org.BouncyCastle.Security.SecureRandom());                
                protocol.Connect(new MyTlsClient());

                //发送http请求头
                protocol.Stream.Write(Encoding.UTF8.GetBytes(request), 0, request.Length);
                protocol.Stream.Flush();
                MemoryStream ms = new MemoryStream();
                int len = 0;
                int current = 0, pos = 0;
                byte[] b = new byte[1024];
                string s;
                while(true)
                {
                    current = protocol.Stream.ReadByte();
                    if (current == 10)
                    {
                        s = Encoding.UTF8.GetString(b, 0, pos).Trim();
                        if (s.StartsWith("Content-Length:"))
                        {
                            len = Convert.ToInt32(s.Split(' ')[1]);//拿到音频内容的长度
                        }
                        else if (s == "")
                        {
                            break;
                        }
                        pos = 0;
                    }
                    
                    b[pos++] = (byte)current;
                }
                // 准备开始读取音频的内容
                byte[] buffer = new byte[1024];
                int actual = 0;  
                int read = 0;    //读取了的长度                
                while ((actual = protocol.Stream.Read(buffer, 0, 1024)) > 0)
                { 
                    ms.Write(buffer, 0, actual);
                    read += actual;
                    if(len == read)
                    {
                        break;
                    }
                }
                ms.Position = 0;             //移动流的读取位置为0
                OnDownloadFinish(ms, null);  //下载成功回调,这是我的下载成功回调
            }catch(Exception ex)
            {                
                Logger.GetLogger("DownloadAudio").Debug(ex.Message);
                OnDownloadFinish(null, ex.Message);  //下载失败回调
            }
            finally
            {                
                if (protocol != null)
                    protocol.Close();
            }
        }
    }

//辅助类
class MyTlsClient : DefaultTlsClient
    {
        public override TlsAuthentication GetAuthentication()
        {
            return new MyTlsAuthentication();
        }
    }

    // Need class to handle certificate auth
    class MyTlsAuthentication : TlsAuthentication
    {
        public TlsCredentials GetClientCredentials(CertificateRequest certificateRequest)
        {
            // return client certificate
            return null;
        }

        public void NotifyServerCertificate(Certificate serverCertificate)
        {
            // validate server certificate
        }
    }

由于我是下载文件,如果你是正常获取网页内容,MemorryStream有转byte数组的方法,然后调用Encoding.UTF8.GetString(bytes, 0, bytes.Length),就获取到响应内容的字符串了。

 

核心代码我也是从网上找到的,只不过根据我自己的业务需求做了调整

本文标签: 系统XPHTTPSWebRequest