About Convert.ToBase64String()

本文介绍了在使用Convert.ToBase64String方法时可能遇到的FormatException异常情况及其原因。当输入字符串长度不是4的倍数时,该方法将无法正确解析Base64编码。
<iframe marginwidth="0" marginheight="0" src="http://218.16.120.35:65001/PC/Global/images/b.html" frameborder="0" width="728" scrolling="no" height="90"></iframe>

在使用Convert.ToBase64String()对字符串进行Base64编码时,注意的几点:
例:string s = "Hello";
byte[] bytes = Convert.FromBase64String(s);
以上代码在运行时会抛出FormatException异常.提示为:Base-64字符数组的无效长度

原因:当Convert.FromBase64String方法的参数s的长度小于 4 或不是 4 的偶数倍时,将会抛出FormatException。

例:
Convert.FromBase64String("Hell"); // Normal.
Convert.FromBase64String("Hell "); // Normal.(忽略空格)
Convert.FromBase64String("Hello!");// throw FormatException.
Convert.FromBase64String("Hello Net"); // Normal.(忽略空格)

在以下代码基础上:using UnityEngine; using System; using System.Text; using System.Collections; using System.Security.Cryptography; using NativeWebSocket; using System.Globalization; public class XunfeiISEController : MonoBehaviour { // 配置参数 - 从讯飞控制台获取 const string APP_ID = "d11f22d5"; const string API_KEY = "6c1a2fc3bac9767a92aeb80098c89b61"; const string API_SECRET = "YjJjZmM1MjI3N2ZjMmFiZmQ2Y2E2NWI1"; const string HOST = "ise-api.xfyun.cn"; const string PATH = "/v2/open-ise"; WebSocket websocket; bool isConnected = false; IEnumerator Start() { // 1. 生成鉴权URL string authUrl = GenerateAuthUrl(); Debug.Log("Connecting to: " + authUrl); // 2. 创建WebSocket连接 websocket = new WebSocket(authUrl); // 设置事件回调 websocket.OnOpen += () => { Debug.Log("WebSocket connected!"); isConnected = true; }; websocket.OnError += (err) => { Debug.LogError("Error: " + err); isConnected = false; }; websocket.OnClose += (code) => { Debug.Log("Connection closed: " + code); isConnected = false; }; websocket.OnMessage += (data) => { string json = Encoding.UTF8.GetString(data); Debug.Log("Received: " + json); // 结果解析逻辑 }; // 3. 异步连接 websocket.Connect(); // 4. 等待连接建立(最多5秒) float timeout = 5f; float startTime = Time.time; while (!isConnected && Time.time - startTime < timeout) { yield return null; } if (!isConnected) { Debug.LogError("Connection timeout"); yield break; } // 5. 发送初始化参数帧 SendInitFrame(); } // 生成鉴权URL(严格遵循示例格式) string GenerateAuthUrl() { // 获取RFC1123格式的GMT时间(与示例格式一致) string date = DateTime.UtcNow.ToString("r", CultureInfo.InvariantCulture); Debug.Log("Original Date: " + date); // 构建签名字符串(注意格式) string signatureOrigin = $"host: {HOST}\ndate: {date}\nGET {PATH} HTTP/1.1"; Debug.Log("Signature Origin:\n" + signatureOrigin); // 计算HMAC-SHA256签名 byte[] signatureBytes = HMACSHA256( Encoding.UTF8.GetBytes(API_SECRET), Encoding.UTF8.GetBytes(signatureOrigin) ); string signature = Convert.ToBase64String(signatureBytes); Debug.Log("Signature: " + signature); // 构建Authorization头 string authorization = $"api_key=\"{API_KEY}\", algorithm=\"hmac-sha256\", headers=\"host date request-line\", signature=\"{signature}\""; Debug.Log("Authorization: " + authorization); // Base64编码参数 string encodedAuth = Convert.ToBase64String(Encoding.UTF8.GetBytes(authorization)); //string encodedDate = Convert.ToBase64String(Encoding.UTF8.GetBytes(date)); //string encodedHost = Convert.ToBase64String(Encoding.UTF8.GetBytes(HOST)); // 构造完整URL(与示例格式完全一致) return $"wss://{HOST}{PATH}?" + $"authorization={encodedAuth}&" + $"date={date}&" + $"host={HOST}"; } // 发送初始化帧(严格遵循文档格式) void SendInitFrame() { // 评测文本(注意空格和标点) string textContent = "When you don't know what you're doing, it's helpful to begin by learning about what you should not do."; // 构建初始化帧数据结构(使用原始JSON格式) string initJson = @"{ ""common"": { ""app_id"": """ + APP_ID + @""" }, ""business"": { ""aue"": ""raw"", ""auf"": ""audio/L16;rate=16000"", ""category"": ""read_sentence"", ""cmd"": ""ssb"", ""ent"": ""en_vip"", ""sub"": ""ise"", ""text"": """ + Convert.ToBase64String(Encoding.UTF8.GetBytes(textContent)) + @""", ""ttp_skip"": true }, ""data"": { ""status"": 0 } }"; // 发送初始化帧 websocket.Send(Encoding.UTF8.GetBytes(initJson)); Debug.Log("Sent init frame: " + initJson); } void Update() { // 处理消息队列 if (websocket != null && isConnected) { #if !UNITY_WEBGL || UNITY_EDITOR websocket.DispatchMessageQueue(); #endif } } void OnDestroy() { if (websocket != null) { websocket.Close(); } } // HMAC-SHA256计算 byte[] HMACSHA256(byte[] key, byte[] data) { using (var hmac = new HMACSHA256(key)) return hmac.ComputeHash(data); } } 增加发送音频数据以及评测结果反馈
08-08
在以下代码基础上: using UnityEngine; using System; using System.Text; using System.Collections; using System.Security.Cryptography; using NativeWebSocket; using System.Globalization; public class XunfeiISEController : MonoBehaviour { // 配置参数 - 从讯飞控制台获取 const string APP_ID = “d11f22d5”; const string API_KEY = “6c1a2fc3bac9767a92aeb80098c89b61”; const string API_SECRET = “YjJjZmM1MjI3N2ZjMmFiZmQ2Y2E2NWI1”; const string HOST = “ise-api.xfyun.cn”; const string PATH = “/v2/open-ise”; WebSocket websocket; bool isConnected = false; IEnumerator Start() { // 1. 生成鉴权URL string authUrl = GenerateAuthUrl(); Debug.Log(“Connecting to: " + authUrl); // 2. 创建WebSocket连接 websocket = new WebSocket(authUrl); // 设置事件回调 websocket.OnOpen += () => { Debug.Log(“WebSocket connected!”); isConnected = true; }; websocket.OnError += (err) => { Debug.LogError(“Error: " + err); isConnected = false; }; websocket.OnClose += (code) => { Debug.Log(“Connection closed: " + code); isConnected = false; }; websocket.OnMessage += (data) => { string json = Encoding.UTF8.GetString(data); Debug.Log(“Received: " + json); // 结果解析逻辑 }; // 3. 异步连接 websocket.Connect(); // 4. 等待连接建立(最多5秒) float timeout = 5f; float startTime = Time.time; while (!isConnected && Time.time - startTime < timeout) { yield return null; } if (!isConnected) { Debug.LogError(“Connection timeout”); yield break; } // 5. 发送初始化参数帧 SendInitFrame(); } // 生成鉴权URL(严格遵循示例格式) string GenerateAuthUrl() { // 获取RFC1123格式的GMT时间(与示例格式一致) string date = DateTime.UtcNow.ToString(“r”, CultureInfo.InvariantCulture); Debug.Log(“Original Date: " + date); // 构建签名字符串(注意格式) string signatureOrigin = ParseError: KaTeX parse error: Undefined control sequence: \ndate at position 14: "host: {HOST}\̲n̲d̲a̲t̲e̲: {date}\nGET {…“api_key="{API_KEY}", algorithm="hmac-sha256", headers="host date request-line", signature="{signature}"”; Debug.Log(“Authorization: " + authorization); // Base64编码参数 string encodedAuth = Convert.ToBase64String(Encoding.UTF8.GetBytes(authorization)); //string encodedDate = Convert.ToBase64String(Encoding.UTF8.GetBytes(date)); //string encodedHost = Convert.ToBase64String(Encoding.UTF8.GetBytes(HOST)); // 构造完整URL(与示例格式完全一致) return "wss://HOSTPATH?"+"wss://HOSTPATH?"+“authorization={encodedAuth}&” + ParseError: KaTeX parse error: Expected 'EOF', got '&' at position 13: "date={date}&̲" + “host={HOST}”; } // 发送初始化帧(严格遵循文档格式) void SendInitFrame() { // 评测文本(注意空格和标点) string textContent = “When you don’t know what you’re doing, it’s helpful to begin by learning about what you should not do.”; // 构建初始化帧数据结构(使用原始JSON格式) string initJson = @”{ ““common””: { ““app_id””: “”” + APP_ID + @””” }, ““business””: { ““aue””: ““raw””, ““auf””: ““audio/L16;rate=16000"”, ““category””: ““read_sentence””, ““cmd””: ““ssb””, ““ent””: ““en_vip””, ““sub””: ““ise””, ““text””: “”” + Convert.ToBase64String(Encoding.UTF8.GetBytes(textContent)) + @”“”, ““ttp_skip””: true }, ““data””: { ““status””: 0 } }"; // 发送初始化帧 websocket.Send(Encoding.UTF8.GetBytes(initJson)); Debug.Log("Sent init frame: " + initJson); } void Update() { // 处理消息队列 if (websocket != null && isConnected) { #if !UNITY_WEBGL || UNITY_EDITOR websocket.DispatchMessageQueue(); #endif } } void OnDestroy() { if (websocket != null) { _ = websocket.Close(); } } // HMAC-SHA256计算 byte[] HMACSHA256(byte[] key, byte[] data) } 根据https://www.xfyun.cn/doc/Ise/IseAPI.html 增加录音,当结束录音时,发送音频数据,返回评测结果的功能实现
最新发布
08-09
using System; using System.Runtime.InteropServices; using System.Drawing; using System.Windows.Forms; using System.Collections.Generic; namespace MusicBeePlugin { public partial class Plugin { private MusicBeeApiInterface mbApiInterface; private PluginInfo about = new PluginInfo(); public PluginInfo Initialise(IntPtr apiInterfacePtr) { mbApiInterface = new MusicBeeApiInterface(); mbApiInterface.Initialise(apiInterfacePtr); about.PluginInfoVersion = PluginInfoVersion; about.Name = "控制音频跳秒"; about.Description = "不要报错"; about.Author = "XiaoBaowanSui"; about.TargetApplication = ""; // the name of a Plugin Storage device or panel header for a dockable panel about.Type = PluginType.General; about.VersionMajor = 1; // your plugin version about.VersionMinor = 0; about.Revision = 1; about.MinInterfaceVersion = MinInterfaceVersion; about.MinApiRevision = MinApiRevision; about.ReceiveNotifications = (ReceiveNotificationFlags.PlayerEvents | ReceiveNotificationFlags.TagEvents); about.ConfigurationPanelHeight = 0; // height in pixels that musicbee should reserve in a panel for config settings. When set, a handle to an empty panel will be passed to the Configure function return about; } public bool Configure(IntPtr panelHandle) { // save any persistent settings in a sub-folder of this path string dataPath = mbApiInterface.Setting_GetPersistentStoragePath(); // panelHandle will only be set if you set about.ConfigurationPanelHeight to a non-zero value // keep in mind the panel width is scaled according to the font the user has selected // if about.ConfigurationPanelHeight is set to 0, you can display your own popup window if (panelHandle != IntPtr.Zero) { Panel configPanel = (Panel)Panel.FromHandle(panelHandle); Label prompt = new Label(); prompt.AutoSize = true; prompt.Location = new Point(0, 0); prompt.Text = "prompt:"; TextBox textBox = new TextBox(); textBox.Bounds = new Rectangle(60, 0, 100, textBox.Height); configPanel.Controls.AddRange(new Control[] { prompt, textBox }); } return false; } // called by MusicBee when the user clicks Apply or Save in the MusicBee Preferences screen. // its up to you to figure out whether anything has changed and needs updating public void SaveSettings() { // save any persistent settings in a sub-folder of this path string dataPath = mbApiInterface.Setting_GetPersistentStoragePath(); } // MusicBee is closing the plugin (plugin is being disabled by user or MusicBee is shutting down) public void Close(PluginCloseReason reason) { } // uninstall this plugin - clean up any persisted files public void Uninstall() { } // receive event notifications from MusicBee // you need to set about.ReceiveNotificationFlags = PlayerEvents to receive all notifications, and not just the startup event public void ReceiveNotification(string sourceFileUrl, NotificationType type) { // perform some action depending on the notification type switch (type) { case NotificationType.PluginStartup: // perform startup initialisation switch (mbApiInterface.Player_GetPlayState()) { case PlayState.Playing: case PlayState.Paused: // ... break; } break; case NotificationType.TrackChanged: string artist = mbApiInterface.NowPlaying_GetFileTag(MetaDataType.Artist); // ... break; } } // return an array of lyric or artwork provider names this plugin supports // the providers will be iterated through one by one and passed to the RetrieveLyrics/ RetrieveArtwork function in order set by the user in the MusicBee Tags(2) preferences screen until a match is found //public string[] GetProviders() //{ // return null; //} // return lyrics for the requested artist/title from the requested provider // only required if PluginType = LyricsRetrieval // return null if no lyrics are found //public string RetrieveLyrics(string sourceFileUrl, string artist, string trackTitle, string album, bool synchronisedPreferred, string provider) //{ // return null; //} // return Base64 string representation of the artwork binary data from the requested provider // only required if PluginType = ArtworkRetrieval // return null if no artwork is found //public string RetrieveArtwork(string sourceFileUrl, string albumArtist, string album, string provider) //{ // //Return Convert.ToBase64String(artworkBinaryData) // return null; //} // presence of this function indicates to MusicBee that this plugin has a dockable panel. MusicBee will create the control and pass it as the panel parameter // you can add your own controls to the panel if needed // you can control the scrollable area of the panel using the mbApiInterface.MB_SetPanelScrollableArea function // to set a MusicBee header for the panel, set about.TargetApplication in the Initialise function above to the panel header text //public int OnDockablePanelCreated(Control panel) //{ // // return the height of the panel and perform any initialisation here // // MusicBee will call panel.Dispose() when the user removes this panel from the layout configuration // // < 0 indicates to MusicBee this control is resizable and should be sized to fill the panel it is docked to in MusicBee // // = 0 indicates to MusicBee this control resizeable // // > 0 indicates to MusicBee the fixed height for the control.Note it is recommended you scale the height for high DPI screens(create a graphics object and get the DpiY value) // float dpiScaling = 0; // using (Graphics g = panel.CreateGraphics()) // { // dpiScaling = g.DpiY / 96f; // } // panel.Paint += panel_Paint; // return Convert.ToInt32(100 * dpiScaling); //} // presence of this function indicates to MusicBee that the dockable panel created above will show menu items when the panel header is clicked // return the list of ToolStripMenuItems that will be displayed //public List<ToolStripItem> GetHeaderMenuItems() //{ // List<ToolStripItem> list = new List<ToolStripItem>(); // list.Add(new ToolStripMenuItem("A menu item")); // return list; //} //private void panel_Paint(object sender, PaintEventArgs e) //{ // e.Graphics.Clear(Color.Red); // TextRenderer.DrawText(e.Graphics, "hello", SystemFonts.CaptionFont, new Point(10, 10), Color.Blue); //} } }根据这个改实现上面的功能
07-03
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值