MNS consumption demo

Updated at:

This topic provides sample code for message receipts in popular programming languages. You can download the corresponding software development kit (SDK) packages to pull messages from a queue.

Downloads

Note

The SDK download links provide the Alibaba Cloud Communications SDK core library for each supported language and the dybaseapi package. The dybaseapi package is used to pull messages from a queue. For languages other than Java and Node.js, you must also install the Alibaba Cloud V2 SDK separately.

Language

SDK download link

Java

Java SDK

Node.js

Node.js V2 SDK

.NET/C#

  • Lightweight Message Queue (formerly MNS) client SDK

    Note

    When you install the Lightweight Message Queue (formerly MNS) client SDK, download the C# SDK package and package it into a .dll file. Alternatively, use the pre-packaged Aliyun.MNS.dll file. Then, add the following content to the csproj file in the Alibaba Cloud Communications SDK package:

    <ItemGroup>
          <PackageReference Include="AlibabaCloud.SDK.Dybaseapi20170525" Version="1.0.1" />
          <Reference Include="AliyunSDK_MNS">
              <HintPath>path\to\AliyunSDK_MNS.dll</HintPath>// Replace this with the path to the .dll file that you packaged or downloaded.
              <Private>true</Private>
          </Reference>
     </ItemGroup>
  • Alibaba Cloud Communications SDK: dybaseapi (.NET)

  • Installation method:

    # dybaseapi SDK:
    dotnet add package AlibabaCloud.SDK.Dybaseapi20170525

Python

  • Lightweight Message Queue (formerly MNS) client SDK: Python SDK

  • Alibaba Cloud Communications SDK: dybaseapi (Python)

  • Installation method:

    # Lightweight Message Queue (MNS) client SDK:
    pip install aliyun-mns-sdk
    # dybaseapi SDK:
    pip install alibabacloud_dybaseapi20170525

Go

  • Lightweight Message Queue (formerly MNS) client SDK: Go SDK

  • Alibaba Cloud Communications SDK: dybaseapi (Go)

  • Installation method:

    # Lightweight Message Queue (MNS) client SDK:
    go get github.com/aliyun/aliyun-mns-go-sdk
    # dybaseapi SDK:
    go get github.com/alibabacloud-go/dybaseapi-20170525

PHP

  • Lightweight Message Queue (formerly MNS) client SDK: PHP SDK

  • Alibaba Cloud Communications SDK: dybaseapi (PHP)

  • Installation method:

    # Lightweight Message Queue (MNS) client SDK:
    composer require aliyun/aliyun-mns-php-sdk -W
    # dybaseapi SDK:
    composer require alibabacloud/dybaseapi-20170525

Notes

When you use the sample demos, note the following information. The Java language is used as an example. The notes for other languages are similar.

  • Configure the AccessKey ID and AccessKey secret.

    To prevent AccessKey pair leaks, do not hard-code your AccessKey pair into your code. Instead, configure environment variables to obtain the AccessKey pair. For more information about how to configure environment variables, see Configure environment variables on Linux, macOS, and Windows systems.

    This topic uses the environment variable names ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET as examples. The following code shows how to retrieve an AccessKey pair from environment variables:

    String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
    String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
  • Replace messageType with the message type you need, such as VoiceReport for subscribing to call record message receipts. For more information about the receipt message types that Voice Service supports, see Introduction to receipt messages and configuration process.

    String messageType="messageType";
  • queueName is the name of the message queue. For example, for call record message reception, you can find it on the Voice Service console > General Settings > Subscribe To Receipt Messages page.

    String queueName="queueName";
  • In the Java sample code, the dealMessage method processes the mobile originated message content that you receive. You can write the business logic for the mobile originated message content in this method. arg represents the receipt message body parameter. Valid values include start_time, end_time, duration, and status_code. You can set the parameter as needed.

    // Parse the message body based on the specific message format in the documentation.
    String arg = (String) contentMap.get("arg");
    // Write your business code here.

Sample demos

Java demo

package com.alicom.mns.sample;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import com.alicom.mns.tools.DefaultAlicomMessagePuller;
import com.alicom.mns.tools.MessageListener;
import com.aliyun.mns.model.Message;
import com.google.gson.Gson;

import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * This can only be used to receive messages from Alibaba Cloud Communications. It cannot be used to receive messages from other services.
 * Demo for receiving receipt messages.
 */
public class ReceiveDemo {

    private static Logger logger = Logger.getLogger(ReceiveDemo.class.getName());

    static class MyMessageListener implements MessageListener {
        private Gson gson = new Gson();

        @Override
        public boolean dealMessage(Message message) {

            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            // Key values of the message
            System.out.println("message receiver time from mns:" + format.format(new Date()));
            System.out.println("message handle: " + message.getReceiptHandle());
            System.out.println("message body: " + message.getMessageBodyAsString());
            System.out.println("message id: " + message.getMessageId());
            System.out.println("message dequeue count:" + message.getDequeueCount());
            System.out.println("Thread:" + Thread.currentThread().getName());
            try {
                Map<String, Object> contentMap = gson.fromJson(message.getMessageBodyAsString(), HashMap.class);

                // TODO: Parse the message body based on the specific message format in the documentation.
                String arg = (String) contentMap.get("arg");

                // TODO: Start writing your business code here.

            } catch (com.google.gson.JsonSyntaxException e) {
                logger.log(Level.SEVERE, "error_json_format:" + message.getMessageBodyAsString(), e);
                // In theory, format errors should not occur. If a format error is encountered, the message must be deleted. Otherwise, redelivery will also result in errors.
                return true;
            } catch (Throwable e) {
                // If an exception is caused by your own code, you should return false. This way, the message is not deleted and will be redelivered based on the policy.
                return false;
            }

            // If the message is processed successfully, return true. The SDK will call the delete method of MNS to delete the message from the queue.
            return true;
        }

    }

    public static void main(String[] args) throws Exception, ParseException {

        DefaultAlicomMessagePuller puller = new DefaultAlicomMessagePuller();

        // Set the size of the asynchronous thread pool, the size of the task queue, and the hibernation period for threads with no data.
        puller.setConsumeMinThreadSize(6);
        puller.setConsumeMaxThreadSize(16);
        puller.setThreadQueueSize(200);
        puller.setPullMsgThreadSize(1);
        // Enable this for joint debugging with the server-side. Do not enable it during normal use because it consumes resources.
        puller.openDebugLog(false);

        // TODO: This is the AccessKey information obtained from the operating system.
        String accessKeyId=System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
	String accessKeySecret=System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");

        /*
         * TODO: Replace messageType and queueName with the message type and queue name you need.
         * For all receipt message types supported by Voice Service, see the following URL:
         * https://help.aliyun.com/document_detail/149938.html
         */

        // This should be replaced with the message type of the corresponding product.
        String messageType = "messageType";
        // After you enable the corresponding service messages on the Alibaba Cloud Communications page, you can obtain the queueName from the page. The format is similar to Alicom-Queue-******-VoiceReport.
        String queueName = "queueName";

        puller.startReceiveMsg(accessKeyId, accessKeySecret, messageType, queueName, new MyMessageListener());
    }


}

Python demo

import os
import time

from alibabacloud_tea_util import models as util_models
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_dybaseapi20170525.client import Client as OpenApiClient
from alibabacloud_dybaseapi20170525.models import QueryTokenForMnsQueueRequest

from datetime import datetime
from mns.account import Account
from mns.queue import *
from mns.mns_exception import *

try:
    import json
except ImportError:
    import simplejson as json

# TODO: Replace this with the message type you need to receive.
# For all receipt message types supported by Voice Service, see the following URL:
# https://help.aliyun.com/document_detail/149938.html
message_type = "VoiceReport"
# TODO: Replace this with your queue name. After you enable the corresponding service messages on the Alibaba Cloud Communications page, you can obtain the queue_name from the page.
queue_name = f"Alicom-Queue-******-VoiceReport"

# This is the fixed endpoint of Alibaba Cloud Communications. Do not modify it.
endpoint = f"https://1943695596114318.mns.cn-hangzhou.aliyuncs.com"

config = open_api_models.Config(
    access_key_id=os.environ['ALIBABA_CLOUD_ACCESS_KEY_ID'],
    access_key_secret=os.environ['ALIBABA_CLOUD_ACCESS_KEY_SECRET']
)
# Set the endpoint.
config.endpoint = f'dybaseapi.aliyuncs.com'
client = OpenApiClient(config)


# The token for Alibaba Cloud Communications services expires. You must dynamically update it.
class Token():
    def __init__(self):
        self.token = None
        self.tmp_access_id = None
        self.tmp_access_key = None
        self.expire_time = None

    def is_refresh(self):
        if self.expire_time is None:
            return 1
        # Compare the expiration time with the current system time. Refresh the token 2 minutes in advance.
        now = datetime.now()
        expire = datetime.strptime(self.expire_time, "%Y-%m-%d %H:%M:%S")
        if expire <= now or (expire - now).seconds < 120:
            return 1
        return 0

    def refresh(self):
        print("start refresh token...")

        request = QueryTokenForMnsQueueRequest()
        request.message_type = message_type
        request.queue_name = queue_name

        runtime = util_models.RuntimeOptions()
        response = client.query_token_for_mns_queue_with_options(request, runtime)
        # print response
        if response is None:
            raise Exception("GET_TOKEN_FAIL", "No response was received when obtaining the token.")

        response_body = response.body
        if response_body.code != "OK":
            raise Exception("GET_TOKEN_FAIL", "Failed to obtain the token.")

        sts_token = response_body.message_token_dto
        self.tmp_access_key = sts_token.access_key_secret
        self.tmp_access_id = sts_token.access_key_id
        self.expire_time = sts_token.expire_time
        self.token = sts_token.security_token

        print("finish refresh token...")


# Initialize token, my_account, and my_queue.
token, my_account, my_queue = Token(), None, None

# Loop to read and delete messages until the queue is empty.
# The receive message request uses long polling. The wait_seconds parameter specifies a long polling period of 3 seconds.

# Long polling details:
## If the queue contains messages, the request returns immediately.
## If the queue is empty, the request hangs on the MNS server for 3 seconds. If a message is written to the queue during this period, the request immediately returns the message. After 3 seconds, the request returns a "no message" response.

wait_seconds = 3
print("%sReceive And Delete Message From Queue%s\nQueueName:%s\nWaitSeconds:%s\n" % (
    10 * "=", 10 * "=", queue_name, wait_seconds))

while True:
    receipt_handles = []
    # Read messages.
    try:
        # Check if the token has expired and needs to be refreshed.
        if token.is_refresh() == 1:
            # Refresh the token.
            token.refresh()
            if my_account:
                my_account.mns_client.close_connection()
                my_account = None
        if not my_account:
            my_account = Account(endpoint, token.tmp_access_id, token.tmp_access_key, token.token)
            my_queue = my_account.get_queue(queue_name)
            my_queue.batch_receive_message(10, wait_seconds)

        # Receive messages.
        recv_msgs = my_queue.batch_receive_message(10, wait_seconds)
        print(recv_msgs)

        for recv_msg in recv_msgs:
            # TODO: Business logic processing.

            # receipt_handles.append(recv_msg.receipt_handle)
            print("Receive Message Succeed! ReceiptHandle:%s MessageBody:%s MessageID:%s" % (
                recv_msg.receipt_handle, recv_msg.message_body, recv_msg.message_id))

    except MNSExceptionBase as e:
        if e.type == "QueueNotExist":
            print("Queue not exist, please create queue before receive message.")
            break
        elif e.type == "MessageNotExist":
            print("Queue is empty! sleep 10s")
            time.sleep(10)
            continue
        print("Receive Message Fail! Exception:%s\n" % e)
        break

    # Delete messages.
    try:
        if len(receipt_handles) > 0:
            # my_queue.batch_delete_message(receipt_handles)
            print("Delete Message Succeed!  ReceiptHandles:%s" % receipt_handles)
    except MNSExceptionBase as e:
        print("Delete Message Fail! Exception:%s\n" % e)

C# demo

using Newtonsoft.Json;
using AlibabaCloud.SDK.Dybaseapi20170525;
using AlibabaCloud.SDK.Dybaseapi20170525.Models;
using Aliyun.MNS.Model;
using Aliyun.MNS;
using System.Text;

namespace AlibabaCloud.SDK.Sample
{
    public class Sample
    {
        

        public static void Main(string[] args)
        {
            AlibabaCloud.OpenApiClient.Models.Config config = new AlibabaCloud.OpenApiClient.Models.Config
                {
                    // Required. Make sure that the ALIBABA_CLOUD_ACCESS_KEY_ID environment variable is set.
                    AccessKeyId = Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_ID"),
                    // Required. Make sure that the ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variable is set.
                    AccessKeySecret = Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_SECRET"),
                };
            config.Endpoint = "dybaseapi.aliyuncs.com";
            Client client = new Client(config);

            // Specify the queue name. After you enable the corresponding service messages on the Alibaba Cloud Communications page, you can obtain the queueName from the page.
            String queueName = "Alicom-Queue-******-VoiceReport";
            
            // Specify the message type. For all receipt message types supported by Voice Service, see the following URL:
            // https://help.aliyun.com/document_detail/149938.html
            String messageType = "VoiceReport"; 
            


            int maxThread = 2;
            for (int i = 0; i < maxThread; i++)
            {
                TestTask testTask = new TestTask("PullMessageTask-thread-" + i, messageType, queueName, client);
                Thread t = new Thread(new ThreadStart(testTask.Handle));
                // Start the thread.
                t.Start();
            }
            Console.ReadKey();

        }
    }
    class TestTask
    {
        object o = new object();
        const int sleepTime = 50;
        const long bufferTime = 60 * 2; // If the expiration time is less than 2 minutes, re-obtain the token to prevent server time errors.
        // This is the fixed endpoint of Alibaba Cloud Communications. Do not modify it.
        const String mnsAccountEndpoint = "https://1943695596114318.mns.cn-hangzhou.aliyuncs.com/";

        public String name { get; private set; }
        public String messageType { get; private set; }
        public String QueueName { get; private set; }
        public int TaskID { get; private set; }
        public Client DybaseapiClient { get; private set; }

        public TestTask(String name, String messageType, String queueName, Client dybaseapiClient)
        {
            this.name = name;
            this.messageType = messageType;
            this.QueueName = queueName;
            this.DybaseapiClient = dybaseapiClient;
        }

        readonly Dictionary<string, QueryTokenForMnsQueueResponseBody.QueryTokenForMnsQueueResponseBodyMessageTokenDTO> tokenMap = new Dictionary<string, QueryTokenForMnsQueueResponseBody.QueryTokenForMnsQueueResponseBodyMessageTokenDTO>();
        readonly Dictionary<string, Queue> queueMap = new Dictionary<string, Queue>();

        public QueryTokenForMnsQueueResponseBody.QueryTokenForMnsQueueResponseBodyMessageTokenDTO GetTokenByMessageType(Client dybaseapiClient, String messageType, String queueName)
        {
            var request = new QueryTokenForMnsQueueRequest
            {
                MessageType = messageType,
                QueueName = queueName
            };
            var queryTokenForMnsQueueResponse = dybaseapiClient.QueryTokenForMnsQueue(request);
            var token = queryTokenForMnsQueueResponse.Body.MessageTokenDTO;
            return token;
        }

        /// Process messages.
        public void Handle()
        {
            while (true)
            {
                try
                {
                    QueryTokenForMnsQueueResponseBody.QueryTokenForMnsQueueResponseBodyMessageTokenDTO token = null;
                    Queue queue = null;
                    lock (o)
                    {
                        if (tokenMap.ContainsKey(messageType))
                        {
                            token = tokenMap[messageType];
                        }

                        if (queueMap.ContainsKey(QueueName))
                        {
                            queue = queueMap[QueueName];
                        }

                        TimeSpan ts = new TimeSpan(0);

                        if (token != null)
                        {
                            DateTime b = Convert.ToDateTime(token.ExpireTime);
                            DateTime c = Convert.ToDateTime(DateTime.Now);
                            ts = b - c;
                        }

                        if (token == null || ts.TotalSeconds < bufferTime || queue == null)
                        {
                            token = GetTokenByMessageType(DybaseapiClient, messageType, QueueName);

                            var client = new MNSClient(token.AccessKeyId, token.AccessKeySecret, mnsAccountEndpoint, token.SecurityToken);
                            queue = client.GetNativeQueue(QueueName);
                            if (tokenMap.ContainsKey(messageType))
                            {
                                tokenMap.Remove(messageType);
                            }
                            if (queueMap.ContainsKey(QueueName))
                            {
                                queueMap.Remove(QueueName);
                            }
                            tokenMap.Add(messageType, token);
                            queueMap.Add(QueueName, queue);
                        }
                    }

                    BatchReceiveMessageResponse batchReceiveMessageResponse = queue.BatchReceiveMessage(16);
                    List<Message> messages = batchReceiveMessageResponse.Messages;

                    for (int i = 0; i <= messages.Count - 1; i++)
                    {
                        try
                        {
                            byte[] outputb = Convert.FromBase64String(messages[i].Body);
                            string orgStr = Encoding.UTF8.GetString(outputb);
                            Console.WriteLine(orgStr);
                            // TODO: Implement the specific consumption logic.
                            // Delete the message after it is successfully consumed.
                            // queue.DeleteMessage(messages[i].ReceiptHandle);
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine(e.ToString());
                        }
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                }
                Thread.Sleep(sleepTime);
            }
        }
    }
}

PHP demo

<?php
use AlibabaCloud\Tea\Utils\Utils\RuntimeOptions;
use Darabonba\OpenApi\Models\Config;
use AlibabaCloud\SDK\Dybaseapi\V20170525\Dybaseapi;
use AlibabaCloud\SDK\Dybaseapi\V20170525\Models\QueryTokenForMnsQueueRequest;
use Exception;

use AliyunMNS\Client;
use AliyunMNS\Requests\BatchReceiveMessageRequest;
use AliyunMNS\Requests\BatchDeleteMessageRequest;

require_once 'vendor/autoload.php';

// An Alibaba Cloud account AccessKey has full permissions for all APIs. We recommend that you use a RAM user for API access or routine O&M.
// We strongly recommend that you do not save your AccessKey ID and AccessKey secret in your project code. Otherwise, the AccessKey pair may be leaked, which compromises the security of all resources in your account.
// This example shows how to save the AccessKey ID and AccessKey secret in environment variables for identity verification.
$config = new Config([
    // Required. Make sure that the ALIBABA_CLOUD_ACCESS_KEY_ID environment variable is set.
    "accessKeyId" => getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"),
    // Required. Make sure that the ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variable is set.
    "accessKeySecret" => getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")
]);
$config->endpoint = "dybaseapi.aliyuncs.com";
$client = new Dybaseapi($config);

// The queue name. Replace this with your queue name.
// After you enable the corresponding service messages on the Alibaba Cloud Communications page, you can obtain the queueName from the page. The format is similar to Alicom-Queue-******-VoiceReport.
$queueName = 'Alicom-Queue-*******-VoiceReport'; 
// The message type to receive. For all receipt message types supported by Voice Service, see the following URL:
// https://help.aliyun.com/document_detail/149938.html
$messageType = 'VoiceReport'; 

$response = null;
$token = null;
$i = 0;

do {
    try {
        if (null == $token || strtotime($token->expireTime) - time() > 2 * 60) {
            $request = new QueryTokenForMnsQueueRequest([
                'messageType' => $messageType,
                'queueName' => $queueName,
            ]);

            $runtime = new RuntimeOptions([]);
            $response = $client->queryTokenForMnsQueueWithOptions($request, $runtime);
            $token = $response->body;
        }

        $token = $response->body->messageTokenDTO;

        echo "receive message\n";
        $mnsClient = new Client(
            "https://1943695596114318.mns.cn-hangzhou.aliyuncs.com",  // This is the fixed endpoint of Alibaba Cloud Communications. Do not modify it.
            $token->accessKeyId,
            $token->accessKeySecret,
            $token->securityToken
        );
        $queue = $mnsClient->getQueueRef($queueName);

        $mnsRequest = new BatchReceiveMessageRequest(10, 5);
        $mnsRequest->setQueueName($queueName);
        $mnsResponse = $queue->batchReceiveMessage($mnsRequest);

        $receiptHandles = [];
        foreach ($mnsResponse->getMessages() as $message) {
            echo $message->getMessageBody() . "\n";
            // User logic:
            // $receiptHandles[] = $message->ReceiptHandle; // Records added to the $receiptHandles array will be deleted.
        }

        if (count($receiptHandles) > 0) {
            $deleteRequest = new BatchDeleteMessageRequest($queueName, $receiptHandles);
            $queue->batchDeleteMessage($deleteRequest);
        }
    } catch (Exception $e) {
         echo $e . PHP_EOL;
        if ($e->getCode() == 404) {
            $i++;
        }
        echo $e . PHP_EOL;
    }
} while ($i < 3);

Go demo

package main

import (
	"encoding/base64"
	"fmt"
	"os"
	"time"

	openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
	dybaseapiClient "github.com/alibabacloud-go/dybaseapi-20170525/client"
	"github.com/alibabacloud-go/tea/tea"
	mns "github.com/aliyun/aliyun-mns-go-sdk"
)

const (
	// This is the fixed endpoint of Alibaba Cloud Communications. Do not modify it.
	mnsDomain = "https://1943695596114318.mns.cn-hangzhou.aliyuncs.com"
	// The queue name. Modify this to the name of the queue from which you want to receive messages.
	// After you enable the corresponding service messages on the Alibaba Cloud Communications page, you can obtain the queueName from the page. The format is similar to Alicom-Queue-******-VoiceReport.
	queueName = "Alicom-Queue-******-VoiceReport"
	// The message type. Modify this to the message type you want to receive. For all receipt message types supported by Voice Service, see the following URL:
	// https://help.aliyun.com/document_detail/149938.html
	messageType = "VoiceReport"
)

func main() {
	// An Alibaba Cloud account AccessKey has full permissions for all APIs. We recommend that you use a RAM user for API access or routine O&M.
	// We strongly recommend that you do not save your AccessKey ID and AccessKey secret in your project code. Otherwise, the AccessKey pair may be leaked, which compromises the security of all resources in your account.
	// This example shows how to save the AccessKey ID and AccessKey secret in environment variables for identity verification.
	// Create a client instance.
	config := &openapi.Config{
		// Required. Make sure that the ALIBABA_CLOUD_ACCESS_KEY_ID environment variable is set.
		AccessKeyId: tea.String(os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")),
		// Required. Make sure that the ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variable is set.
		AccessKeySecret: tea.String(os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")),
	}
	config.Endpoint = tea.String("dybaseapi.aliyuncs.com")
	client, _err := dybaseapiClient.NewClient(config)
	if _err != nil {
		panic(_err)
	}

	cstLoc, _ := time.LoadLocation("Asia/Shanghai")
	var token *dybaseapiClient.QueryTokenForMnsQueueResponseBodyMessageTokenDTO
	var expireTime time.Time

	// Loop to read messages.
	for {
		// If the token expires, re-obtain it.
		if token == nil || expireTime.Unix()-time.Now().Unix() < 2*60 {
			request := &dybaseapiClient.QueryTokenForMnsQueueRequest{}
			request.MessageType = tea.String(messageType)
			request.QueueName = tea.String(queueName)
			response, err := client.QueryTokenForMnsQueue(request)
			if err != nil {
				panic(err)
			}
			token = response.Body.MessageTokenDTO
			expireTime, err = time.ParseInLocation("2006-01-02 15:04:05", *token.ExpireTime, cstLoc)
			if err != nil {
				panic(err)
			}
		}

		clientConfig := mns.AliMNSClientConfig{
			EndPoint:        mnsDomain,
			AccessKeyId:     *token.AccessKeyId,
			AccessKeySecret: *token.AccessKeySecret,
			Token:           *token.SecurityToken,
		}
		mnsClient := mns.NewAliMNSClientWithConfig(clientConfig)
		queue := mns.NewMNSQueue(queueName, mnsClient)

		endChan := make(chan int)
		respChan := make(chan mns.BatchMessageReceiveResponse)
		errChan := make(chan error)
		// Message processing coroutine.
		go func() {
			select {
			case resp := <-respChan:
				{
					// Message response processing. When a message is received through respChan:
					// fmt.Printf("response: %+v\n", resp)

					// Process each message.
					for _, msg := range resp.Messages {
						// Parse the message.
						messageBody, decodeErr := base64.StdEncoding.DecodeString(msg.MessageBody)
						if decodeErr != nil {
							panic(decodeErr)
						}
						fmt.Println("message body: ", string(messageBody))
						// todo: Business logic processing.

						if ret, e := queue.ChangeMessageVisibility(msg.ReceiptHandle, 5); e != nil {
							fmt.Printf("ChangeMessageVisibility: %+v\n", e)
						} else {
							fmt.Printf("visibility changed: %+v\n", ret)
							fmt.Println("delete it now: ", ret.ReceiptHandle)

							// After the visibility changes, use queue.DeleteMessage to delete the message.
							if e := queue.DeleteMessage(ret.ReceiptHandle); e != nil {
								fmt.Println(e)
							}
						}
					}

					endChan <- 1
				}
			case <-errChan:
				{
					// todo: Error handling. When an error is received through errChan:
					// fmt.Println(err)

					endChan <- 1
				}
			}
		}()

		// Receive messages.
		queue.BatchReceiveMessage(respChan, errChan, 10, 5)
		<-endChan
	}
}

FAQ

SSL certificate verification failed ("SSL: CERTIFICATE_VERIFY_FAILED") when integrating the Python SDK on macOS

What causes the "SSL: CERTIFICATE_VERIFY_FAILED" exception when I integrate the Python SDK in a macOS environment? (WebSocket closed due to [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to retrieve local issuer certificate (_ssl.c:1000)).

When you connect to a WebSocket, OpenSSL may fail to verify the certificate and report that the certificate cannot be found. This issue is usually caused by incorrect certificate configurations in the Python environment. You can follow these steps to manually locate and fix the certificate issue:

  1. Export system certificates and set environment variables: Run the following commands to export all certificates from the macOS system to a file. Then, set this file as the default certificate path for Python and related libraries.

    security find-certificate -a -p > ~/all_mac_certs.pem
    export SSL_CERT_FILE=~/all_mac_certs.pem
    export REQUESTS_CA_BUNDLE=~/all_mac_certs.pem
  2. Create a symbolic link to fix the Python OpenSSL configuration: If the Python OpenSSL configuration is missing a certificate, you can run the following command to manually create a symbolic link. Make sure to replace the path in the command with the actual installation directory of your local Python version.

    # 3.9 is an example version number. Adjust the path based on the Python version installed on your local machine.
    ln -s /etc/ssl/* /Library/Frameworks/Python.framework/Versions/3.9/etc/openssl
  3. Restart the terminal and clear the cache: After you complete the preceding operations, close and reopen the terminal to make sure that the environment variables take effect. Clear any possible cache and try to connect to the WebSocket again.

These steps can resolve connection issues caused by incorrect certificate configurations. If the issue persists, check whether the certificate configuration of the destination server is correct.

The Java V1.0 SDK throws NoClassDefFoundError: javax/xml/bind/DatatypeConverter in JDK 17

Problem description: When you run the receipt message consumption demo (ReceiveDemo) of the Java V1.0 SDK in a JDK 17 environment, the PullMessageTask-thread-0 message pull thread throws java.lang.NoClassDefFoundError: javax/xml/bind/DatatypeConverter. The stack trace shows Caused by: java.lang.ClassNotFoundException: javax.xml.bind.DatatypeConverter, and message consumption fails.

Cause: The V1.0 SDK (alicom-mns-receive-sdk 1.1.3 and aliyun-sdk-mns 1.1.9.1) uses javax.xml.bind.DatatypeConverter to sign requests, in the com.aliyuncs.auth.HmacSHA1Signer.signString method. This class was removed from the JDK in JDK 11 as part of the JAXB removal, so it is not available in JDK 17.

Solution: Upgrade to the V2.0 SDK (aliyun-sdk-mns 2.0.0). The V2.0 SDK provides its own signing implementation, which is based on com.aliyun.mns.common.auth.ServiceSignature and HmacSHA1Signature, and performs Base64 encoding by using BinaryUtil.toBase64String(). This removes the dependency on javax.xml.bind. In a JDK 17 environment, HmacSHA1Signature.computeHashAndBase64Encode("test-data", "test-key") returns Signature: 9jvRgqkBouhkeWqiBmhw4iTijrE= and no NoClassDefFoundError is thrown.

Add the following dependency to the pom.xml file of your project:

<dependency>
    <groupId>com.aliyun.mns</groupId>
    <artifactId>aliyun-sdk-mns</artifactId>
    <version>2.0.0</version>
</dependency>