Todos os produtos
Search
Central de documentação

Alibaba Cloud SDK:Corpo da requisição e mecanismo de assinatura V2 estilo ROA

Última atualização: Jul 03, 2026

Assine e envie requisições HTTP estilo ROA para a Alibaba Cloud OpenAPI com o mecanismo de assinatura V2.

Importante

Este método de acesso não é mais recomendado. Utilize o Corpo da requisição e mecanismo de assinatura V3.

Estrutura da requisição HTTP

Uma requisição completa à OpenAPI inclui as partes a seguir.

Nome

Obrigatório

Descrição

Exemplo

Protocolo

Sim

Protocolo da requisição. Consulte os metadados da OpenAPI para verifique os protocolos suportados. Prefira HTTPS quando disponível.

https://

Endpoint

Sim

Endpoint do serviço. Verifique a documentação específica do produto para obter o endpoint correto.

bailian.cn-beijing.aliyuncs.com

resource_URI_parameters

Sim

URL da API, incluindo caminho e parâmetros de consulta.

/{WorkspaceId}/datacenter/category

RequestHeader

Sim

Cabeçalho da requisição com versão da API, Host e Authorization. Definição na seção RequestHeader abaixo.

Accept:application/json

Authorization:acs YourAccessKeyId:s8ZMF/eAIvvPJwehLLha0bVNFJ0=

Content-MD5:LP54yxk8n7KqF1PPgbJizw==

Content-Type:application/json

Date:Wed, 16 Apr 2025 03:44:46 GMT

Host:bailian.cn-beijing.aliyuncs.com

x-acs-signature-method:HMAC-SHA1

x-acs-signature-nonce:ef34aae7-7bd2-413d-a541-680cd2c48538

x-acs-signature-version:1.0

x-acs-version:2023-12-29

RequestBody

Sim

Corpo da requisição com parâmetros de negócio. Teste requisições no Portal do Desenvolvedor da Alibaba Cloud OpenAPI.

{"CategoryName":"test","CategoryType":"UNSTRUCTURED"}

HTTPMethod

Sim

Método HTTP: PUT, POST, GET ou DELETE. O método necessário consta no documento da API.

POST

RequestHeader

O RequestHeader contém os campos a seguir.

Nome

Tipo

Obrigatório

Descrição

Exemplo

Accept

String

Não

Formato da resposta. O estilo ROA suporta apenas application/json.

application/json

Content-MD5

String

Não

Hash MD5 de 128 bits do RequestBody codificado em Base64.

LP54yxk8n7KqF1PPgbJizw==

Date

String

Sim

Timestamp atual no formato GMT do HTTP 1.1. Validade de 15 minutos.

Wed, 16 Apr 2025 03:44:46 GMT

Host

String

Sim

Endpoint do serviço. Deve corresponder ao endpoint indicado na Estrutura da requisição HTTP.

bailian.cn-beijing.aliyuncs.com

x-acs-signature-method

String

Obrigatório para requisições não anônimas

Algoritmo de assinatura. Valor fixo: HMAC-SHA1.

HMAC-SHA1

x-acs-signature-nonce

String

Sim

Número aleatório único para evitar ataques de replay. Diferente em cada requisição.

ef34aae7-7bd2-413d-a541-680cd2c48538

x-acs-signature-version

String

Não

Versão da assinatura. Valor fixo: 1.0.

1.0

x-acs-version

String

Sim

Versão da API. Consulte a versão no Portal do Desenvolvedor da Alibaba Cloud OpenAPI ou nos metadados da OpenAPI.

2023-12-29

Authorization

String

Obrigatório para requisições não anônimas

String de autenticação no formato AccessKeyId:Signature. Encontre seu AccessKey ID no console RAM. Crie uma AccessKey.

Signature é a assinatura da requisição, calculada conforme o Mecanismo de assinatura.

acs YourAccessKeyId:D9uFJAJgLL+dryjBfQK+YeqGtoY=

Mecanismo de assinatura

Todas as requisições exigem assinatura para autenticação. O API Gateway da Alibaba Cloud recalcula a assinatura com base nos parâmetros e cabeçalhos da requisição e a compara com a assinatura enviada para validar identidade e integridade dos dados. Calcule a assinatura seguindo estas etapas:

Nota

Requisições e respostas usam codificação UTF-8.

Etapa 1: Construir os cabeçalhos canônicos

Os cabeçalhos canônicos (CanonicalizedHeaders) são cabeçalhos HTTP não padrão com prefixo x-acs-. Construa-os assim:

  1. Converta os nomes dos cabeçalhos x-acs- do RequestHeader para minúsculas e ordene-os lexicograficamente.

  2. Remova espaços à esquerda e à direita dos nomes e valores dos cabeçalhos.

  3. Adicione \n após cada cabeçalho (inclusive o último) e concatene todos para formar os CanonicalizedHeaders.

Exemplo:

x-acs-signature-method:HMAC-SHA1
x-acs-signature-nonce:ef34aae7-7bd2-413d-a541-680cd2c48538
x-acs-signature-version:1.0
x-acs-version:2023-12-29

Etapa 2: Construir o recurso canônico

Construa o recurso canônico (CanonicalizedResource) conforme descrito abaixo:

  1. Ordene os parâmetros da string de consulta por nome, em ordem lexicográfica, e una-os com &.

  2. Anexe a string de consulta ordenada ao caminho do recurso usando ?. O caminho do recurso é o segmento da URL entre o host e a string de consulta, começando com /. Se não houver string de consulta, use apenas o caminho do recurso.

Exemplo:

/llm-p2e4XXXXXXXXsvtn/datacenter/category

Etapa 3: Construir a string a ser assinada

Monte a string a ser assinada (stringToSign) com este pseudocódigo:

String stringToSign = 
    HTTPMethod + "\n" +
    Accept + "\n" +
    ContentMD5 + "\n" +
    ContentType + "\n" +
    Date + "\n" +
    CanonicalizedHeaders +
    CanonicalizedResource

Parâmetro

Descrição

HTTPMethod

Método HTTP em maiúsculas, como POST ou GET.

Accept

Valor do cabeçalho Accept. String vazia se ausente.

ContentMD5

Valor do cabeçalho Content-MD5. String vazia se ausente.

ContentType

Valor do cabeçalho Content-Type. String vazia se ausente.

Nota

Tipo MIME do RequestBody.

Date

Valor do cabeçalho Date.

CanonicalizedHeaders

Cabeçalhos canônicos da Etapa 1: Construir os cabeçalhos canônicos.

CanonicalizedResource

Recurso canônico da Etapa 2: Construir o recurso canônico.

Exemplo:

POST
application/json
LP54yxk8n7KqF1PPgbJizw==
application/json
Wed, 16 Apr 2025 03:44:46 GMT
x-acs-signature-method:HMAC-SHA1
x-acs-signature-nonce:ef34aae7-7bd2-413d-a541-680cd2c48538
x-acs-signature-version:1.0
x-acs-version:2023-12-29
/llm-p2e4XXXXXXXXsvtn/datacenter/category

Etapa 4: Calcular a assinatura

Conforme a RFC2104, assine a string da Etapa 3 com HMAC-SHA1 e codifique o resultado em Base64.

String signature = Base64(HMAC_SHA1(SigningKey, stringToSign))
Importante

SigningKey corresponde ao segredo da sua AccessKey. Crie uma AccessKey.

Exemplo:

s8ZMF/eAIvvPJwehLLha0bVNFJ0=

Etapa 5: Construir o cabeçalho Authorization

Defina o cabeçalho Authorization com o valor a seguir.

String Authorization = "acs " + AccessKeyId + ":" + signature

Exemplo de valor:

acs YourAccessKeyId:s8ZMF/eAIvvPJwehLLha0bVNFJ0=

Etapa 6: Adicionar a assinatura à requisição e enviá-la

POST https://bailian.cn-beijing.aliyuncs.com/llm-p2e4XXXXXXXXsvtn/datacenter/category HTTP/1.1
 
Accept:application/json
Authorization:acs YourAccessKeyId:r8Y9ZqVhTrYGl4nieqk7CW0Pwow=
Content-MD5:LP54yxk8n7KqF1PPgbJizw==
Content-Type:application/json
Date:Wed, 16 Apr 2025 06:47:10 GMT
Host:bailian.cn-beijing.aliyuncs.com
x-acs-signature-method:HMAC-SHA1
x-acs-signature-nonce:e3d8efa7-b1d8-42f3-9733-4fe2691e15dc
x-acs-signature-version:1.0
x-acs-version:2023-12-29

{"CategoryName":"test","CategoryType":"UNSTRUCTURED"}

Código de exemplo de assinatura

Exemplo em Java

Nota

Executa no JDK 1.8. Ajuste conforme seu ambiente.

Adicione estas dependências Maven ao arquivo pom.xml.

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.13</version>
</dependency>
<dependency>
     <groupId>com.google.code.gson</groupId>
     <artifactId>gson</artifactId>
     <version>2.9.0</version>
 </dependency>
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.apache.http.client.methods.*;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;

public class SignatureDemo {
    public static class SignatureRequest {
        private final String httpMethod;
        private final String host;
        private final String version;
        private final String canonicalUri;

        public TreeMap<String, String> headers = new TreeMap<>();
        public TreeMap<String, Object> queryParams = new TreeMap<>();
        public byte[] bodyByteArray;

        public SignatureRequest(String httpMethod, String host, String version, String canonicalUri) {
            this.httpMethod = httpMethod;
            this.host = host;
            this.version = version;
            this.canonicalUri = canonicalUri;
            initHeaders();
        }

        private void initHeaders() {
            headers.put("Host", host);
            headers.put("x-acs-version", version);
            headers.put("x-acs-signature-version", "1.0");
            headers.put("Accept", "application/json");
            headers.put("x-acs-signature-nonce", java.util.UUID.randomUUID().toString());
            headers.put("Date", getGmtDate());
            headers.put("x-acs-signature-method", "HMAC-SHA1");
        }

        private String getGmtDate() {
            SimpleDateFormat gmtFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.ENGLISH);
            gmtFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
            return gmtFormat.format(new Date());
        }

        public void setBody(Map<String, String> body, ContentType contentType) {
            Gson gson = (new GsonBuilder()).disableHtmlEscaping().create();
            this.bodyByteArray = gson.toJson(body).getBytes(StandardCharsets.UTF_8);
            headers.put("Content-MD5", md5Sum(this.bodyByteArray));
            headers.put("Content-Type", contentType.getMimeType());
        }
    }

    private static final String ACCESS_KEY_ID = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
    private static final String ACCESS_KEY_SECRET = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
    private static final String ALGORITHM_NAME = "HmacSHA1";

    public static void main(String[] args) {
        // Example 1: POST request
        String method = "POST";
        String host = "bailian.cn-beijing.aliyuncs.com";
        String version = "2023-12-29";
        String canonicalUri = "/llm-p2e4XXXXXXXXsvtn/datacenter/category";
        SignatureRequest signatureRequest = new SignatureRequest(method, host, version, canonicalUri);
        Map<String, String> body = new HashMap<>();
        body.put("CategoryName", "test");
        body.put("CategoryType", "UNSTRUCTURED");
        System.out.println(new Gson().toJson(body));
        signatureRequest.setBody(body, ContentType.APPLICATION_JSON);

        /*// Example 2: GET request
        String method = "GET";
        String host = "bailian.cn-beijing.aliyuncs.com";
        String version = "2023-12-29";
        String canonicalUri = "/llm-p2e4XXXXXXXXsvtn/datacenter/files";
        SignatureRequest signatureRequest = new SignatureRequest(method, host, version, canonicalUri);
        signatureRequest.queryParams.put("CategoryId", "cate_a946*********************_10045991");*/

        /*// Example 3: DELETE request
        String method = "DELETE";
        String host = "bailian.cn-beijing.aliyuncs.com";
        String version = "2023-12-29";
        String canonicalUri = "/llm-p2e4XXXXXXXXsvtn/datacenter/category/cate_a946*********************_10045991";
        SignatureRequest signatureRequest = new SignatureRequest(method, host,  version, canonicalUri);*/

        // Generate Authorization
        generateSignature(signatureRequest);
        // Send the request using HTTPClient
        callApi(signatureRequest);
    }

    private static void generateSignature(SignatureRequest signatureRequest) {
        try {
            // Step 1: Construct the canonicalized headers
            String canonicalHeaders = buildCanonicalHeaders(signatureRequest);
            // Step 2: Construct the canonicalized resource
            String canonicalQueryString = buildQueryString(signatureRequest);
            // Step 3: Construct the string to sign
            String stringToSign = buildStringToSign(signatureRequest, canonicalQueryString, canonicalHeaders);
            // Step 4: Construct the signature string
            String signature = signString(stringToSign);
            // Step 5: Construct the Authorization header
            String authorization = "acs " + ACCESS_KEY_ID + ":" + signature;
            signatureRequest.headers.put("Authorization", authorization);
        } catch (Exception ex) {
            throw new IllegalArgumentException(ex.toString());
        }
    }

    private static void callApi(SignatureRequest signatureRequest) {
        try {
            // Send the request using HttpClient
            String url = "https://" + signatureRequest.host + signatureRequest.canonicalUri;
            URIBuilder uriBuilder = new URIBuilder(url);
            // Add request parameters
            signatureRequest.queryParams.forEach((key, value) -> uriBuilder.addParameter(key, String.valueOf(value)));
            HttpUriRequest httpRequest;
            switch (signatureRequest.httpMethod) {
                case "GET":
                    httpRequest = new HttpGet(uriBuilder.build());
                    break;
                case "POST":
                    HttpPost httpPost = new HttpPost(uriBuilder.build());
                    if (signatureRequest.bodyByteArray != null) {
                        httpPost.setEntity(new ByteArrayEntity(signatureRequest.bodyByteArray, ContentType.create(signatureRequest.headers.get("Content-Type"))));
                    }
                    httpRequest = httpPost;
                    break;
                case "PUT":
                    HttpPut httpPut = new HttpPut(uriBuilder.build());
                    if (signatureRequest.bodyByteArray != null) {
                        httpPut.setEntity(new ByteArrayEntity(signatureRequest.bodyByteArray, ContentType.create(signatureRequest.headers.get("Content-Type"))));
                    }
                    httpRequest = httpPut;
                    break;
                case "DELETE":
                    httpRequest = new HttpDelete(uriBuilder.build());
                    break;
                default:
                    System.out.println("Unsupported HTTP method: " + signatureRequest.httpMethod);
                    throw new IllegalArgumentException("Unsupported HTTP method");
            }
            // Add HTTP request headers
            signatureRequest.headers.forEach(httpRequest::addHeader);
            // Send the request
            try (CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpResponse response = httpClient.execute(httpRequest)) {
                String result = EntityUtils.toString(response.getEntity(), "UTF-8");
                System.out.println(result);
            } catch (IOException e) {
                // Handle exceptions
                System.out.println("Failed to send request");
                throw new IllegalArgumentException(e.toString());
            }
        } catch (URISyntaxException e) {
            // Handle exceptions
            System.out.println("Invalid URI syntax");
            throw new IllegalArgumentException(e.toString());
        }
    }

    private static String buildCanonicalHeaders(SignatureRequest signatureRequest) {
        StringBuilder canonicalHeaders = new StringBuilder();
        signatureRequest.headers.entrySet().stream()
                .filter(entry -> entry.getKey().startsWith("x-acs-"))
                .forEach(entry -> canonicalHeaders.append(entry.getKey().toLowerCase().trim()).append(":").append(entry.getValue().trim()).append("\n"));
        return canonicalHeaders.toString();
    }

    private static String buildQueryString(SignatureRequest signatureRequest) {
        StringBuilder queryBuilder = new StringBuilder(signatureRequest.canonicalUri);
        if (!signatureRequest.queryParams.isEmpty()) {
            queryBuilder.append("?");
        }

        for (Map.Entry<String, Object> entry : signatureRequest.queryParams.entrySet()) {
            queryBuilder.append(entry.getKey());
            String value = (String) entry.getValue();
            if (value != null && !value.isEmpty()) {
                queryBuilder.append("=").append(value).append("&");
            } else {
                queryBuilder.append("&");
            }
        }
        String queryString = queryBuilder.toString();
        if (queryString.endsWith("&")) {
            queryString = queryString.substring(0, queryString.length() - 1);
        }
        return queryString;
    }

    private static String buildStringToSign(SignatureRequest signatureRequest, String canonicalQueryString, String canonicalHeaders) {
        StringBuilder sb = new StringBuilder();
        sb.append(signatureRequest.httpMethod).append("\n");
        appendIfPresent(sb, signatureRequest.headers.get("Accept"));
        appendIfPresent(sb, signatureRequest.headers.get("Content-MD5"));
        appendIfPresent(sb, signatureRequest.headers.get("Content-Type"));
        appendIfPresent(sb, signatureRequest.headers.get("Date"));
        sb.append(canonicalHeaders);
        sb.append(canonicalQueryString);
        return sb.toString();
    }

    private static void appendIfPresent(StringBuilder sb, String value) {
        if (value != null) {
            sb.append(value).append("\n");
        } else {
            sb.append("\n");
        }
    }

    private static String signString(String stringToSign) {
        try {
            Mac mac = Mac.getInstance(ALGORITHM_NAME);
            mac.init(new SecretKeySpec(ACCESS_KEY_SECRET.getBytes(StandardCharsets.UTF_8), ALGORITHM_NAME));
            byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
            return DatatypeConverter.printBase64Binary(signData);
        } catch (NoSuchAlgorithmException | InvalidKeyException ex) {
            throw new IllegalArgumentException(ex.toString());
        }
    }

    public static String md5Sum(byte[] buff) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] md5Bytes = md.digest(buff);
            return DatatypeConverter.printBase64Binary(md5Bytes);
        } catch (NoSuchAlgorithmException ex) {
            throw new IllegalArgumentException(ex.toString());
        }
    }
}

Este exemplo crie um gatilho de aplicação com a operação Container Service for Kubernetes (CS) CreateTrigger. Considere AccessKey ID como testid, segredo da AccessKey como testsecret, x-acs-signature-nonce como 15215528852396 e Data como Tue 9 Apr 2022 07:35:29 GMT. Etapas do cálculo da assinatura:

  1. Construa os cabeçalhos canônicos.

x-acs-signature-method:HMAC-SHA1
x-acs-signature-nonce:15215528852396
x-acs-signature-version:1.0
x-acs-version:2015-12-15
  1. Construa o recurso canônico.

/clusters/test_cluster_id/triggers
  1. Construa a string a ser assinada.

POST
application/json
Gtl/0jNYHf8t9Lq8Xlpaqw==
application/json
Tue 9 Apr 2022 07:35:29 GMT
x-acs-signature-method:HMAC-SHA1
x-acs-signature-nonce:15215528852396
x-acs-signature-version:1.0
x-acs-version:2015-12-15
/clusters/test_cluster_id/triggers
  1. Calcule a assinatura.

acs testid:D9uFJAJgLL+dryjBfQK+YeqGtoY=
  1. Adicione a assinatura à requisição.

POST /clusters/test_cluster_id/triggers HTTP/1.1
 /* headers */
{
    "accept": "application/json",
    "date": "Tue 9 Apr 2022 07:35:29 GMT",
    "host": "cs.cn-hangzhou.aliyuncs.com",
    "x-acs-signature-nonce": "15215528852396",
    "x-acs-signature-method": "HMAC-SHA1",
    "x-acs-signature-version": "1.0",
    "x-acs-version": "2015-12-15",
    "content-type": "application/json",
    "content-md5": "Gtl/0jNYHf8t9Lq8Xlpaqw==",
    "authorization": "acs testid:D9uFJAJgLL+dryjBfQK+YeqGtoY="
}
/* body */
{
    "project_id": "default/nginx-test",
    "cluster_id": "test_cluster_id",
    "action": "redeploy",
    "type": "deployment"
}

Referências

Diferenciar estilos ROA e RPC.