其他问题

更新时间:
复制为 MD 格式

消息收发问题

查询队列消息为什么返回404?

存在两种情况:

1)队列不存在,则返回404。

2)队列中没有消息,则等待waitseconds时间之后返回404。长轮询的最大等待时间为30秒。

更多信息,请参见ReceiveMessage使用限制

MNS拉取消息为什么会延迟?

MNS采用分布式存储架构,一个拉取请求的目标节点不一定恰好是存储消息的节点,因此可能出现消息拉取延迟。

您可以通过以下方式减少延迟:

1)将长轮询改为短轮询。

2)增加消费者数量。

MessageNotExist为什么在服务器上无法过滤返回null?

问题现象

调用MNS queue.batchPopMessage()返回404并报错MessageNotExist,在本地环境中可以正常适配返回null,但在服务器环境中无法过滤该错误。

原因

服务端不过滤MessageNotExist错误,是为了将该状态返回给客户端,以便客户端根据业务场景按需重新发起请求。服务端不会永久挂起(hang)等待消息。

清空队列之后,未发送消息但过了一段时间又出现了消息?

清空队列操作只会清理队列中尚未被消费的消息。已被拉取但未ACK确认的消息相当于已出队,不会被清空操作处理。

如果这些正在被消费的消息超过了消息可见时间(VisibilityTimeout)仍未返回ACK,消息会重新变为可见状态,回到队列中。这就是清空队列后仍然出现消息的原因。

MNS支持消息优先级(Priority)设置吗?

不支持。MNS不提供消息优先级设置功能。

开启日志功能后,消费者空拉会打印日志吗?

不会。消费者空拉(即队列中无消息时的拉取操作)不会产生日志记录。

网络与访问问题

MNS的内网访问地址是否只要同地域就能访问?

是的。MNS的内网访问地址只要在同一地域内即可正常访问。

MNSHTTP推送消息时是否只能走公网?

目前MNSHTTP推送仅支持公网。只要网络可达即可正常推送。如果您有私网推送的需求,请提交工单反馈。

MNSHTTP订阅目标为API网关时,网关返回400导致消息无法到达业务侧?

问题原因:MNS服务端推送消息到API网关时被拒绝。

请检查HTTP订阅时配置的消息格式(JSON、XMLSimplified)是否与API网关的要求一致。

API网关会对请求体(Body)进行MD5校验,MNS也会计算MD5校验值并放入Content-MD5头部。如果两端校验结果不一致,API网关会直接返回400错误。

事件触发与订阅问题

通过事件总线获取队列中以#开头的消息时拿不到消息体?

当同时满足以下条件时,以#开头的消息通过事件总线获取时会丢失消息体:

1)向MNS主题发送消息,且消息投递到订阅的队列中。

2)通过MNS发送的消息未进行Base64编码。

3)在事件总线上配置事件源时,未勾选Base64编码解析选项。

这是业界通用组件的解析行为,存在兼容性风险,暂不做特殊处理。建议您在发送消息到MNS之前,先对消息内容进行Base64编码。

MNS触发FC(函数计算)时报错怎么办?

报错现象

MNS通知FC时报错500,错误信息为ConvertErrorConvertNull。

原因及解决方案

该报错通常是因为创建订阅时选择了不兼容的消息格式。FC仅支持STREAMJSON格式。如果您通过SDK创建订阅,可能会误选为Simplified格式,从而导致该报错。请将订阅的消息格式修改为STREAMJSON。

OSS创建MNS规则触发FC时报错怎么办?

原因

FC的触发器仅支持JSONSTREAM格式。直接从OSS创建事件规则并触发FC时,默认的消息格式为Simplified,会导致触发失败。

解决方案

建议从OSS创建事件规则时不要同时创建目标。规则创建完成后,在FC侧创建MNS触发器,即可正常触发。

OSS创建事件规则时创建跨账号订阅报错怎么办?

目前不支持在创建OSS事件规则时同时创建跨账号订阅。

如果确实需要跨账号订阅,可以分两步操作:

1)在OSS创建事件规则时,选择"一对多订阅",将订阅填写内容清空后提交保存。此时需要订阅到MNS的主题。

2)点击刚创建的事件规则,选择"查看订阅详情"跳转到MNS控制台,然后在对应的Topic下创建跨账号订阅。

权限与账号问题

RAM如何设置清除队列消息的权限(MNS:PurgeQueue)?

PurgeQueue操作目前不支持资源级鉴权,因此在RAM授权策略中,Resource字段必须设置为*

MNS点击立即开通时提示实例ID不唯一是什么原因?

这通常是由于系统存在短暂延迟导致的。建议您等待一段时间后,刷新控制台页面重试即可。

开发与集成问题

C# MNS签名鉴权示例代码?

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

public class MnsClient
{
    private readonly string _accessKeyId;
    private readonly string _accessKeySecret;
    private readonly string _accountId;
    private readonly string _region;
    private readonly HttpClient _httpClient;

    public MnsClient(string accessKeyId, string accessKeySecret, string accountId, string region = "cn-hangzhou")
    {
        _accessKeyId = accessKeyId;
        _accessKeySecret = accessKeySecret;
        _accountId = accountId;
        _region = region;
        _httpClient = new HttpClient();
    }

    public async Task SendMessageAsync(string queueName, string messageBody)
    {
        var endpoint = $"https://{_accountId}.mns.{_region}.aliyuncs.com";
        var uri = $"/queues/{queueName}/messages";
        var url = endpoint + uri;

        // 1) 构造消息XML
        var xml = $@"<?xml version=""1.0"" encoding=""UTF-8""?>
<Message>
  <MessageBody>{SecurityElement.Escape(messageBody)}</MessageBody>
</Message>";

        // 2) Content & headers
        var content = new StringContent(xml, Encoding.UTF8, "text/xml");
        string contentType = content.Headers.ContentType!.ToString();
        string date = DateTime.UtcNow.ToString("r");
        string contentMd5 = CalculateBase64Md5(xml);

        // 3) 组装签名参数
        var parameters = new Dictionary<string, string>(StringComparer.Ordinal)
        {
            ["method"] = "POST",
            ["content-md5"] = contentMd5,
            ["content-type"] = contentType,
            ["uri"] = uri,
            ["x-mns-version"] = "2015-06-06"
        };

        string signContent = BuildSignContent(parameters, date);

        // 4) 签名:HMAC-SHA1(secret, signContent) + Base64
        string signature = ComputeSignatureHmacSha1Base64(signContent, _accessKeySecret);

        using var request = new HttpRequestMessage(HttpMethod.Post, url);
        request.Content = content;
        request.Content.Headers.ContentMD5 = Convert.FromBase64String(contentMd5);
        request.Headers.Date = DateTimeOffset.Parse(date);
        request.Headers.TryAddWithoutValidation("x-mns-version", "2015-06-06");
        request.Headers.Authorization = new AuthenticationHeaderValue("MNS", $"{_accessKeyId}:{signature}");

        var response = await _httpClient.SendAsync(request);
        if (!response.IsSuccessStatusCode)
        {
            var error = await response.Content.ReadAsStringAsync();
            throw new Exception($"MNS Error: {response.StatusCode}\n{error}\n\nsignContent:\n{signContent}");
        }
    }

    private static string BuildSignContent(IDictionary<string, string> parameter, string date)
    {
        var sb = new StringBuilder(256);
        AppendIfExist(sb, parameter, "method", true);
        AppendIfExist(sb, parameter, "content-md5", true);
        AppendIfExist(sb, parameter, "content-type", true);
        sb.Append(date).Append('\n');

        var sorted = new SortedDictionary<string, string>(StringComparer.Ordinal);
        foreach (var kv in parameter)
        {
            if (kv.Key.StartsWith("x-mns-", StringComparison.Ordinal))
                sorted[kv.Key] = kv.Value ?? string.Empty;
        }
        foreach (var kv in sorted)
        {
            sb.Append(kv.Key.Trim()).Append(':').Append((kv.Value ?? string.Empty).Trim()).Append('\n');
        }
        AppendIfExist(sb, parameter, "uri", false);
        return sb.ToString();
    }

    private static void AppendIfExist(StringBuilder sb, IDictionary<string, string> parameter, string key, bool newLine)
    {
        if (parameter.TryGetValue(key, out var val) && val != null)
            sb.Append(val);
        if (newLine) sb.Append('\n');
    }

    private static string CalculateBase64Md5(string input)
    {
        using var md5 = MD5.Create();
        var hash = md5.ComputeHash(Encoding.UTF8.GetBytes(input));
        return Convert.ToBase64String(hash);
    }

    private static string ComputeSignatureHmacSha1Base64(string signContent, string accessKeySecret)
    {
        using var hmac = new HMACSHA1(Encoding.UTF8.GetBytes(accessKeySecret));
        var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(signContent));
        return Convert.ToBase64String(hash);
    }
}