You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 6迁移.NET 8后Azure Functions队列消息自动转为byte[]问题

问题

将Azure Functions项目从.NET 6迁移至.NET 8后,队列消息处理出现异常:

  • .NET 6中可直接将队列消息读取为string类型,正常执行Base64解码;
  • 迁移后发送代码未变更,但队列消息默认以byte[]类型接收。若仍用string作为QueueTrigger参数,会触发**"无法将指定代码页的字节转换为Unicode"错误;使用byte[]虽能处理消息,但会收到"消息体含非UTF-8字节"**的警告。

咨询:是否存在.NET 8或Azure Functions的配置项,可指定队列消息以string类型接收,无需修改发送逻辑?


发送消息代码

var message = JsonSerializer.Serialize(batch);
var compressedMessage = Compression.CompressMessage(message);

if (compressedMessage.Length > 64 * 1024)
{
    _logger.LogError("Compressed message size exceeds Azure Queue limit.");
    throw new InvalidOperationException("Message size exceeds Azure Queue limit after compression.");
}

await queueClient.SendMessageAsync(Convert.ToBase64String(compressedMessage));
_logger.LogInformation($"Batch with {batch.Count} items pushed to queue.");

.NET 6接收函数

public async Task ProcessBatchFromQueue(
    [QueueTrigger("test-queue", Connection = "AzureWebJobsStorage")] string compressedMessageBase64,
    ILogger log)
{
    try
    {
        log.LogInformation("Processing batch from queue...");
        var compressedMessage = Convert.FromBase64String(compressedMessageBase64);
        var decompressedMessage = Compression.DecompressMessage(compressedMessage);
        var batch = JsonSerializer.Deserialize<IReadOnlyCollection<InventoryProduct>>(decompressedMessage);
    }
    catch (Exception ex)
    {
        log.LogError($"Error: {ex.Message}");
    }
}

.NET 8接收函数

[Function("ProcessBatchFromQueue")]
public async Task ProcessBatchFromQueue([QueueTrigger("test-queue", Connection = "AzureWebJobsStorage")] byte[] compressedMessageBase64)
{
    try
    {
        _logger.LogInformation("Processing batch from queue...");

        string decompressedMessage = Compression.DecompressMessage(compressedMessageBase64);

        var batch = JsonSerializer.Deserialize<IReadOnlyCollection<InventoryProduct>>(decompressedMessage);
    }
    catch (Exception ex)
    {
        _logger.LogError($"Error: {ex.Message}");
    }
}

压缩解压逻辑

using System.IO.Compression;

public static class Compression
{
    /// <summary>
    /// Compresses a string using GZip.
    /// </summary>
    public static byte[] CompressMessage(string message)
    {
        using (var memoryStream = new MemoryStream())
        {
            using (var gzipStream = new GZipStream(memoryStream, CompressionMode.Compress))
            using (var writer = new StreamWriter(gzipStream))
            {
                writer.Write(message);
                writer.Flush();
            }

            return memoryStream.ToArray();
        }
    }

    /// <summary>
    /// Decompresses a GZip-compressed string.
    /// </summary>
    public static string DecompressMessage(byte[] compressedMessage)
    {
        using (var memoryStream = new MemoryStream(compressedMessage))
        using (var gzipStream = new GZipStream(memoryStream, CompressionMode.Decompress))
        using (var reader = new StreamReader(gzipStream))
        {
            return reader.ReadToEnd();
        }
    }
}

警告日志

[2025-02-28T01:37:19.025Z] Batch with 200 items pushed to queue.
[2025-02-28T01:37:19.115Z] Queue message's body cannot be converted to string because it contains non-UTF8 bytes, message id=d8887de8-f2d8-40cf-8990-555ss7b280d6
[2025-02-28T01:37:19.131Z] Queue message's body cannot be converted to string because it contains non-UTF8 bytes, message id=d8887de8-f2d8-40cf-8990-555ss7b280d6
[2025-02-28T01:37:19.135Z] Queue message's body cannot be converted to string because it contains non-UTF8 bytes, message id=d8887de8-f2d8-40cf-8990-555ss7b280d6
[2025-02-28T01:37:19.137Z] Executing 'Functions.ProcessBatchFromQueue' (Reason='New queue message detected on 'test-queue'.', Id=a148187e-9f70-4bb9-b9df-8446d1b337d7)
[2025-02-28T01:37:19.139Z] Trigger Details: MessageId: d8887de8-f2d8-40cf-8990-555ss7b280d6, DequeueCount: 1, InsertedOn: 2025-02-28T01:37:19.000+00:00

错误日志

[2025-02-28T02:09:56.143Z] Trigger Details: MessageId: 27ad4e9b-86a1-4e9b-9596-7f697424e58a, DequeueCount: 4, InsertedOn: 2025-02-28T02:09:53.000+00:00
[2025-02-28T02:09:56.148Z] Executed 'Functions.ProcessBatchFromQueue' (Failed, Id=4bb49420-5b7c-43ad-adc4-2870d3a3e382, Duration=7ms)
[2025-02-28T02:09:56.150Z] System.Private.CoreLib: Exception while executing function: Functions.ProcessBatchFromQueue. Microsoft.Azure.WebJobs.Host: Exception binding parameter 'compressedMessageBase64'. System.Private.CoreLib: Unable to translate bytes [8B] at index 1 from specified code page to Unicode.

解决方案

方案1:通过配置强制以字符串接收消息

在local.settings.json(本地开发)或Azure门户的应用程序设置中添加以下配置:

{
  "Values": {
    "AzureWebJobsStorage": "...",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
    "AzureWebJobsQueue__MessageEncoding": "Base64"
  }
}

该配置会告知QueueTrigger将所有队列消息视为Base64编码的字符串,直接传递给string类型参数,无需自动解码字节流。配置后即可恢复.NET 6的接收逻辑,继续使用string类型参数处理消息。

方案2:调整接收逻辑兼容现有发送代码(无需修改发送端)

如果不想添加全局配置,可在接收函数中使用byte[]参数,手动将字节转换为Base64字符串后按原逻辑处理:

[Function("ProcessBatchFromQueue")]
public async Task ProcessBatchFromQueue([QueueTrigger("test-queue", Connection = "AzureWebJobsStorage")] byte[] messageBytes)
{
    try
    {
        _logger.LogInformation("Processing batch from queue...");
        // 将字节数组转换为Base64字符串,匹配发送端的编码逻辑
        string compressedMessageBase64 = Convert.ToBase64String(messageBytes);
        var compressedMessage = Convert.FromBase64String(compressedMessageBase64);
        var decompressedMessage = Compression.DecompressMessage(compressedMessage);
        var batch = JsonSerializer.Deserialize<IReadOnlyCollection<InventoryProduct>>(decompressedMessage);
    }
    catch (Exception ex)
    {
        _logger.LogError($"Error: {ex.Message}");
    }
}

这种方式可避免转换错误,同时完全兼容原发送逻辑。

消除"非UTF-8字节"警告

警告是因为SDK会尝试将消息体转换为字符串用于日志记录,即使使用byte[]接收也会触发。可通过配置禁用消息内容日志:

{
  "Values": {
    "AzureWebJobsQueue__LogMessageContent": false
  }
}

内容的提问来源于stack exchange,提问作者Wookappa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 05:04:59