All Products
Search
Document Center

Simple Message Queue (formerly MNS):Protokol permintaan

Last Updated:Mar 11, 2026

Simple Message Queue (formerly MNS), atau SMQ, menggunakan permintaan API berbasis HTTP. Topik ini mencakup sintaksis permintaan, header umum, format respons, dan penandatanganan permintaan.

Penting

SDK SMQ menangani penandatanganan permintaan secara otomatis. Gunakan SDK kecuali Anda perlu membuat permintaan HTTP mentah secara manual.

Sintaksis permintaan

Wilayah dan titik akhir

SMQ tersedia di beberapa wilayah. Setiap wilayah menyediakan titik akhir publik dan titik akhir internal. Untuk detailnya, lihat Wilayah dan titik akhir.

Metode permintaan

SMQ mendukung metode HTTP PUT, POST, GET, dan DELETE. Pastikan parameter permintaan, header permintaan, dan badan permintaan valid. Semua permintaan dan respons menggunakan pengkodean UTF-8.

Parameter umum

Header permintaan umum

HeaderWajibDeskripsi
AuthorizationYaString autentikasi. Lihat Tandatangani permintaan.
Content-LengthYaUkuran badan permintaan dalam byte.
Content-TypeYaJenis MIME dari badan permintaan. Nilai yang valid: text dan xml.
Content-MD5TidakHash MD5 dari badan permintaan. Lihat RFC 1864.
DateYaStempel waktu permintaan dalam GMT. SMQ menolak permintaan yang lebih dari 15 menit lalu.
HostWajib untuk HTTP/1.1, opsional untuk HTTP/1.0Server SMQ. Format: $AccountId.mns.cn-hangzhou.aliyuncs.com. Ganti $AccountId dengan ID akun Alibaba Cloud Anda, yang tersedia di Alibaba Cloud console.
x-mns-versionYaVersi API. Versi saat ini: 2015-06-06.
x-mns-dateTidakMenggantikan header Date ketika client tidak mendukung Date.

Header respons umum

HeaderDeskripsi
Content-LengthUkuran badan respons dalam byte.
ConnectionStatus koneksi HTTP.
DateStempel waktu respons dalam GMT.
ServerNama server SMQ.
x-mns-request-idID permintaan unik. Sertakan nilai ini saat Anda membuka tiket dukungan.
x-mns-versionVersi API. Versi saat ini: 2015-06-06.

Format respons

Kode status HTTP 2xx menunjukkan keberhasilan, sedangkan kode status HTTP 4xx dan 5xx menunjukkan kegagalan. Respons sukses menggunakan format XML:

<?xml version="1.0" encoding="utf-8"?>
<RootElement xmlns="http://mns.aliyuncs.com/doc/v1/">
  <!-- Data respons -->
</RootElement>

Respons kesalahan juga menggunakan XML dan mencakup kode kesalahan, pesan kesalahan, ID permintaan, serta ID host. ID permintaan bersifat unik secara global.

<?xml version="1.0" encoding="utf-8"?>
<Error xmlns="http://mns.aliyuncs.com/doc/v1/">
  <Code>ErrorCode</Code>
  <Message>Pesan kesalahan deskriptif.</Message>
  <RequestId>Request ID</RequestId>
  <HostId>Host ID</HostId>
</Error>

Untuk daftar lengkap kode kesalahan, lihat Kode kesalahan.

Metode penandatanganan permintaan

SMQ mengautentikasi setiap permintaan API melalui signature dalam header Authorization. Proses penandatanganan terdiri dari tiga langkah:

  1. Buat string-to-sign — Susun metode HTTP, header, dan jalur resource menjadi string kanonikal.

  2. Hitung signature — Hash string-to-sign dengan rahasia AccessKey Anda menggunakan HMAC-SHA1, lalu encode hasilnya dengan Base64.

  3. Tambahkan signature ke permintaan — Atur header Authorization menjadi MNS <AccessKey ID>:<Signature>.

Langkah 1: Buat string-to-sign

Buat StringToSign dengan menggabungkan nilai-nilai berikut, dipisahkan oleh karakter baris baru (\n):

StringToSign = HttpMethod + "\n"
             + CONTENT-MD5 + "\n"
             + CONTENT-TYPE + "\n"
             + DATE + "\n"
             + CanonicalizedMNSHeaders
             + CanonicalizedResource
KomponenDeskripsi
HttpMethodMetode HTTP dalam huruf kapital: PUT, GET, POST, atau DELETE.
CONTENT-MD5Hash MD5 dari badan permintaan. Biarkan kosong jika header Content-MD5 tidak diatur.
CONTENT-TYPEJenis MIME dari badan permintaan. Biarkan kosong jika header Content-Type tidak diatur.
DATEStempel waktu permintaan dalam GMT. Contoh: Thu, 07 Mar 2012 18:49:58 GMT. Jika Anda menggunakan header x-mns-date sebagai pengganti Date, gunakan nilai tersebut di sini. SMQ mengembalikan kode kesalahan 400 jika stempel waktu lebih dari 15 menit lalu. Lihat Kode kesalahan.
CanonicalizedMNSHeadersSemua header HTTP yang diawali dengan x-mns-, diproses sebagai berikut: ubah nama header menjadi huruf kecil, urutkan secara alfabetis, lalu gabungkan setiap header sebagai <name>:<value>\n.
CanonicalizedResourceURI dari resource yang diminta, dengan domain dan port dihapus. Misalnya, http://123.123.XX.XX:8080/api/test?code=200 menghasilkan /api/test?code=200, dan http://www.aliyun.com/mns/help menghasilkan /mns/help.

Contoh pembuatan CanonicalizedMNSHeaders (Java):

// Dapatkan semua header permintaan
Map<String, String> httpHeaders = request.getHeaders();
// Urutkan header dan ubah nama menjadi huruf kecil
sortHeadersKeyAndToLowerCase(httpHeaders);
// Gabungkan header x-mns-*
Set<String> keySet = httpHeaders.keySet();
for (String key : keySet) {
    if (key.startsWith("x-mns-")) {
        CanonicalizedMNSHeaders.append(key).append(":")
            .append(httpHeaders.get(key)).append("\n");
    }
}
Penting

Jika terdapat gerbang atau proxy transit lain dalam sistem Anda, gunakan URI dari permintaan HTTP asli untuk CanonicalizedResource, bukan URI yang dilihat oleh gerbang perantara.

Langkah 2: Hitung signature

Terapkan HMAC-SHA1 (RFC 2104) pada StringToSign yang telah diencode UTF-8, menggunakan rahasia AccessKey Anda sebagai kunci. Kemudian encode hasilnya dengan Base64:

Signature = Base64( HMAC-SHA1( AccessSecret, UTF-8-Encoding-Of(StringToSign) ) )
KomponenDeskripsi
Base64Pengkodean Base64.
HMAC-SHA1Algoritma HMAC-SHA1 yang didefinisikan dalam RFC 2104.
AccessSecretRahasia AccessKey yang sesuai dengan ID AccessKey dalam header Authorization.
StringToSignString yang dibuat pada Langkah 1.

Langkah 3: Tambahkan signature ke permintaan

Atur header Authorization:

Authorization: MNS <AccessKey ID>:<Signature>

Contoh:

Authorization: MNS 15B4D3461F177624****:xQE0diMbL****f3YB+FIEXAMPLE=

Contoh penandatanganan berdasarkan bahasa

Contoh berikut menunjukkan cara menghasilkan nilai header Authorization untuk permintaan SMQ.

Python

import base64
import hashlib
import hmac
import os
from datetime import datetime, timezone


def sign_request(access_key_id, access_key_secret, method, resource,
                 content_type="", content_md5="", mns_headers=None):
    """Hasilkan header Authorization untuk permintaan SMQ."""
    date = datetime.now(timezone.utc).strftime("%a, %d %b %Y %H:%M:%S GMT")

    # Bangun CanonicalizedMNSHeaders
    canonicalized_headers = ""
    if mns_headers:
        for key in sorted(mns_headers.keys()):
            canonicalized_headers += f"{key.lower()}:{mns_headers[key]}\n"

    string_to_sign = (
        f"{method}\n{content_md5}\n{content_type}\n{date}\n"
        f"{canonicalized_headers}{resource}"
    )

    signature = base64.b64encode(
        hmac.new(
            access_key_secret.encode("utf-8"),
            string_to_sign.encode("utf-8"),
            hashlib.sha1,
        ).digest()
    ).decode("utf-8")

    return {
        "Authorization": f"MNS {access_key_id}:{signature}",
        "Date": date,
        "x-mns-version": "2015-06-06",
    }


# Penggunaan
headers = sign_request(
    access_key_id=os.environ["ALIBABA_CLOUD_ACCESS_KEY_ID"],
    access_key_secret=os.environ["ALIBABA_CLOUD_ACCESS_KEY_SECRET"],
    method="PUT",
    resource="/queues/examplequeue?metaOverride=true",
    content_type="text/xml",
    mns_headers={"x-mns-version": "2015-06-06"},
)

Java

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

public class MnsSignature {

    public static Map<String, String> signRequest(
            String accessKeyId, String accessKeySecret,
            String method, String resource,
            String contentType, String contentMd5,
            Map<String, String> mnsHeaders) throws Exception {

        String date = DateTimeFormatter.RFC_1123_DATE_TIME
                .format(ZonedDateTime.now(ZoneOffset.UTC));

        // Bangun CanonicalizedMNSHeaders
        StringBuilder canonicalizedHeaders = new StringBuilder();
        if (mnsHeaders != null) {
            TreeMap<String, String> sorted = new TreeMap<>();
            mnsHeaders.forEach((k, v) -> sorted.put(k.toLowerCase(), v));
            sorted.forEach((k, v) -> canonicalizedHeaders.append(k)
                    .append(":").append(v).append("\n"));
        }

        String stringToSign = method + "\n" + contentMd5 + "\n"
                + contentType + "\n" + date + "\n"
                + canonicalizedHeaders + resource;

        Mac mac = Mac.getInstance("HmacSHA1");
        mac.init(new SecretKeySpec(
                accessKeySecret.getBytes(StandardCharsets.UTF_8), "HmacSHA1"));
        String signature = Base64.getEncoder().encodeToString(
                mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8)));

        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", "MNS " + accessKeyId + ":" + signature);
        headers.put("Date", date);
        headers.put("x-mns-version", "2015-06-06");
        return headers;
    }
}

Go

package main

import (
	"crypto/hmac"
	"crypto/sha1"
	"encoding/base64"
	"fmt"
	"os"
	"sort"
	"strings"
	"time"
)

func signRequest(accessKeyID, accessKeySecret, method, resource,
	contentType, contentMD5 string, mnsHeaders map[string]string) map[string]string {

	date := time.Now().UTC().Format(time.RFC1123)

	// Bangun CanonicalizedMNSHeaders
	var keys []string
	for k := range mnsHeaders {
		keys = append(keys, strings.ToLower(k))
	}
	sort.Strings(keys)

	var canonicalized strings.Builder
	for _, k := range keys {
		canonicalized.WriteString(fmt.Sprintf("%s:%s\n", k, mnsHeaders[k]))
	}

	stringToSign := fmt.Sprintf("%s\n%s\n%s\n%s\n%s%s",
		method, contentMD5, contentType, date,
		canonicalized.String(), resource)

	mac := hmac.New(sha1.New, []byte(accessKeySecret))
	mac.Write([]byte(stringToSign))
	signature := base64.StdEncoding.EncodeToString(mac.Sum(nil))

	return map[string]string{
		"Authorization": fmt.Sprintf("MNS %s:%s", accessKeyID, signature),
		"Date":          date,
		"x-mns-version": "2015-06-06",
	}
}

func main() {
	headers := signRequest(
		os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"),
		os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"),
		"PUT",
		"/queues/examplequeue?metaOverride=true",
		"text/xml", "",
		map[string]string{"x-mns-version": "2015-06-06"},
	)
	for k, v := range headers {
		fmt.Printf("%s: %s\n", k, v)
	}
}

Contoh penandatanganan

Contoh berikut menunjukkan permintaan bertanda tangan lengkap dan respons kesalahan umum.

Permintaan contoh

PUT /queues/$queueName?metaOverride=true HTTP/1.1
Host: $AccountId.mns.cn-hangzhou.aliyuncs.com
Date: Wed, 08 Mar 2012 12:00:00 GMT
Authorization: MNS 15B4D3461F177624****:xQE0diMbL****f3YB+FIEXAMPLE=

<?xml version="1.0" encoding="UTF-8"?>
<Queue xmlns="http://mns.aliyuncs.com/doc/v1/">
  <VisibilityTimeout>60</VisibilityTimeout>
  <MaximumMessageSize>1024</MaximumMessageSize>
  <MessageRetentionPeriod>120</MessageRetentionPeriod>
  <DelaySeconds>30</DelaySeconds>
</Queue>

Respons kesalahan

Tabel berikut merangkum kesalahan umum terkait autentikasi.

SkenarioStatus HTTPKode kesalahan
ID AccessKey tidak ada atau dinonaktifkan403AccessIDAuthError
Header Date tidak ada atau tidak valid403InvalidArgument
Permintaan tiba lebih dari 15 menit setelah stempel waktu408TimeExpired

Contoh 1

403 AccessIDAuthError — ID AccessKey tidak ada atau dinonaktifkan:

Content-Type: text/xml
Content-Length: 314
Date: Wed, 18 Mar 2012 08:04:06 GMT
x-mns-request-id: 512B2A634403E52B1956****

<?xml version="1.0" encoding="utf-8"?>
<Error xmlns="http://mns.aliyuncs.com/doc/v1/">
  <Code>AccessIDAuthError</Code>
  <Message>
    Autentikasi AccessID gagal, harap periksa AccessID Anda dan coba lagi.
  </Message>
  <RequestId>512B2A634403E52B1956****</RequestId>
  <HostId>mns.cn-hangzhou.aliyuncs.com</HostId>
</Error>

Contoh 2

403 InvalidArgument — Header Date tidak ada atau tidak valid:

Content-Type: text/xml
Content-Length: 274
Date: Wed, 18 Mar 2012 08:04:06 GMT
x-mns-request-id: 512B2A634403E52B1956****

<?xml version="1.0" encoding="UTF-8"?>
<Error xmlns="http://mns.aliyuncs.com/doc/v1/">
  <Code>InvalidArgument</Code>
  <Message>Header Date tidak valid atau tidak ada.</Message>
  <RequestId>7E1A5CF258F535884403****</RequestId>
  <HostId>mns.cn-hangzhou.aliyuncs.com</HostId>
</Error>

Contoh 3

408 TimeExpired — Permintaan tiba lebih dari 15 menit setelah stempel waktu:

Content-Type: text/xml
Content-Length: 283
Date: Wed, 11 May 2011 09:01:51 GMT
x-mns-request-id: 512B2A634403E52B1956****

<?xml version="1.0" encoding="UTF-8"?>
<Error xmlns="http://mns.aliyuncs.com/doc/v1/">
  <Code>TimeExpired</Code>
  <Message>
    Permintaan HTTP yang Anda kirim telah kedaluwarsa.
  </Message>
  <RequestId>512B2A634403E52B1956****</RequestId>
  <HostId>mns.cn-hangzhou.aliyuncs.com</HostId>
</Error>