使用
sp_invoke_external_rest_endpoint
从 Azure SQL 中,消息已成功在 Azure 队列中排队。有效负载是<QueueMessage><MessageText>HelloWorld</MessageText></QueueMessage>
。
当队列触发的 Azure 函数使消息出队时,它最终会进入有害队列。
如果我采用相同的消息(在本例中为HelloWorld),并通过门户添加它(仅在选中“以 Base64 编码消息正文”时才有效),则消息成功出列。
我尝试了多种方法来了解后台发生的事情,但我已经没有想法了。
这感觉像是一个编码问题。关于如何最好地解决这个问题有什么想法吗?
如果想要重新创建体验,下面是一些代码。 SQL 代码(Azure SQL 数据库)
DECLARE @QueueMessage_XML nvarchar(max) = N'<QueueMessage><MessageText>HelloWorld</MessageText></QueueMessage>';
DECLARE @QueueMessage nvarchar(max) = @QueueMessage_XML;
DECLARE @Time datetime = SYSUTCDATETIME();
DECLARE @FormattedMoment nvarchar(50) = FORMAT(@Time, 'ddd, dd MMM yyyy HH:mm:ss' ) + ' GMT';
DECLARE @ContentType nvarchar(256) = N'"content-type":"application/xml"';
DECLARE @Accept nvarchar(256) = N'"accept":"application/xml"';
DECLARE @StorageApiMsVersion nvarchar(256) = N'"x-ms-version":"2023-11-03"';
DECLARE @MsDate nvarchar(256) = N'"x-ms-date":"' + @FormattedMoment + N'"';
DECLARE @HeadersArray table([HeaderItem] nvarchar(256) NOT NULL);
INSERT INTO @HeadersArray ([HeaderItem]) VALUES
(@ContentType),
(@Accept),
(@StorageApiMsVersion),
(@MsDate);
DECLARE @Headers nvarchar(4000) = N'{' + (SELECT STRING_AGG([HeaderItem], ',') FROM @HeadersArray) + N'}';
DECLARE @Method nvarchar(6) = N'POST';
DECLARE @TimeoutSeconds int = 30;
DECLARE @Response nvarchar(max) = N'';
DECLARE @VisibilityTimeoutSeconds int = 20;
DECLARE @AccountName nvarchar(256) = N'stacctname';
DECLARE @QueueName nvarchar(256) = N'request';
DECLARE @QueueEndpoint nvarchar(256) = N'https://' + @AccountName + N'.queue.core.windows.net';
DECLARE @Url nvarchar(4000) = @QueueEndpoint + N'/' + @QueueName + N'/messages';
DECLARE @ReturnValue int = 0;
EXEC @ReturnValue = sp_invoke_external_rest_endpoint
@url = @Url,
@payload = @QueueMessage,
@headers = @Headers,
@method = @Method,
@credential = [https://stacctname.queue.core.windows.net],
@timeout = @TimeoutSeconds,
@response = @Response OUTPUT;
SELECT @ReturnValue AS [ReturnValue], @Response AS [Response];
Azure 函数应用程序代码
using Azure.Storage.Queues.Models;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;
namespace FunctionApp;
public class DequeueRequest(ILogger<DequeueRequest> logger)
{
private readonly ILogger<DequeueRequest> _logger = logger;
[Function(nameof(DequeueRequest))]
public void Run([QueueTrigger("request", Connection = "AzureWebJobsStorage")] QueueMessage message)
{
//intentionally muted
_ = message.Body;
}
}
更新 我主要缩小了范围,以确保该值是从 SQL
BASE64_ENCODE(CAST(@Payload_String AS varbinary(max)))
中进行 base64 编码的。它几乎可以解决这个问题,但是当尝试 JSON 序列化从队列中拉出的字符串时,它会抛出一个我无法跟踪的错误。原始字符串是有效的并确认可以通过序列化,因此这是关于从队列中拉出并发送到 json 序列化程序时发生的转换。
IOW,如下确认反序列化成功
var request = JsonSerializer.Deserialize<Request>(
@"{""RequestId"":80,""StartDate"":""1753-01-01T00:00:00"",""EndDate"":""9999-12-29T00:00:00""}")
下面失败并将消息变成有毒消息(其中消息正文应该是base64字符串)
var request = JsonSerializer.Deserialize<Request>(message.Body.ToString());
已解决(至少是一个工作解决方案。作为替代工作解决方案,可能会提高效率或减少“必须做的事情”)
顶级域名;DR ...
<MessageText>
<QueueMessage><MessageText>base64_encoded_value</MessageText></QueueMessage>
我的基本经验测试表明 BASE64_ENCODE 必须 是非 unicode 值的 varbinary(至少对于我的问题所需的字符)。