Tous les produits
Search
Centre de documentation

Alibaba Cloud SDK:Corps de requête et mécanisme de signature V2 de style ROA

Dernière mise à jour :Aug 11, 2026

Signez et envoyez des requêtes HTTP de style ROA vers Alibaba Cloud OpenAPI à l'aide du mécanisme de signature V2.

Important

Cette méthode d'accès n'est plus recommandée. Utilisez plutôt le mécanisme de corps de requête et de signature V3.

Structure de la requête HTTP

Une requête OpenAPI complète se compose des éléments suivants.

Nom

Obligatoire

Description

Exemple

Protocole

Oui

Protocole de la requête. Consultez les métadonnées OpenAPI pour connaître les protocoles pris en charge. Privilégiez HTTPS lorsqu'il est disponible.

https://

Endpoint

Oui

Endpoint du service. Reportez-vous à la documentation spécifique au produit pour obtenir l'endpoint correspondant.

bailian.cn-beijing.aliyuncs.com

resource_URI_parameters

Oui

URL de l'API, comprenant le chemin d'accès et les paramètres de requête.

/{WorkspaceId}/datacenter/category

RequestHeader

Oui

En-tête de la requête, incluant la version de l'API, l'hôte (Host) et l'autorisation (Authorization). Ces champs sont détaillés dans la section RequestHeader ci-dessous.

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

Oui

Corps de la requête contenant les paramètres métier. Testez vos requêtes sur le Portail développeur OpenAPI d'Alibaba Cloud.

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

HTTPMethod

Oui

Méthode HTTP : PUT, POST, GET ou DELETE. La méthode requise est indiquée dans le document de l'API.

POST

RequestHeader

Le RequestHeader comprend les champs suivants.

Nom

Type

Obligatoire

Description

Exemple

Accept

String

Non

Format de réponse attendu. Le style ROA prend uniquement en charge application/json.

application/json

Content-MD5

String

Non

Hachage MD5 128 bits du RequestBody, encodé en Base64.

LP54yxk8n7KqF1PPgbJizw==

Date

String

Oui

Horodatage actuel au format GMT HTTP 1.1. Valable pendant 15 minutes.

Wed, 16 Apr 2025 03:44:46 GMT

Host

String

Oui

Endpoint du service. Cette valeur doit correspondre à l'endpoint indiqué dans la section Structure de la requête HTTP.

bailian.cn-beijing.aliyuncs.com

x-acs-signature-method

String

Requis pour les requêtes non anonymes

Algorithme de signature. Valeur fixe : HMAC-SHA1.

HMAC-SHA1

x-acs-signature-nonce

String

Oui

Nombre aléatoire unique destiné à prévenir les attaques par rejeu. Cette valeur doit être différente pour chaque requête.

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

x-acs-signature-version

String

Non

Version de la signature. Valeur fixe : 1.0.

1.0

x-acs-version

String

Oui

Version de l'API. Vous trouverez cette information sur le Portail développeur OpenAPI d'Alibaba Cloud ou dans les métadonnées OpenAPI.

2023-12-29

Authorization

String

Requis pour les requêtes non anonymes

Chaîne d'authentification au format AccessKeyId:Signature. Récupérez votre AccessKey ID dans la console RAM. Créez une AccessKey si nécessaire.

La signature correspond à la signature de la requête, calculée selon le mécanisme de signature.

acs YourAccessKeyId:D9uFJAJgLL+dryjBfQK+YeqGtoY=

Mécanisme de signature

Toute requête doit comporter une signature à des fins d'authentification. La passerelle API d'Alibaba Cloud recalcule cette signature à partir des paramètres et des en-têtes de la requête, puis la compare à la signature soumise afin de vérifier l'identité de l'appelant et l'intégrité des données. Procédez comme suit pour calculer la signature :

Remarque

Les requêtes et les réponses utilisent l'encodage UTF-8.

Étape 1 : Construire les en-têtes canoniques

Les en-têtes canoniques (CanonicalizedHeaders) correspondent aux en-têtes HTTP non standard préfixés par x-acs-. Construisez-les en suivant ces étapes :

  1. Convertissez en minuscules les noms des en-têtes x-acs- issus du RequestHeader, puis triez-les par ordre lexicographique.

  2. Supprimez les espaces superflus au début et à la fin des noms et des valeurs des en-têtes.

  3. Ajoutez \n après chaque en-tête (y compris le dernier), puis concaténez l'ensemble pour former les CanonicalizedHeaders.

Exemple :

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

Étape 2 : Construire la ressource canonique

Construisez la ressource canonique (CanonicalizedResource) comme suit :

  1. Triez les paramètres de la chaîne de requête par nom selon l'ordre lexicographique, puis assemblez-les avec le caractère &.

  2. Accolez la chaîne de requête triée au chemin de la ressource en utilisant le séparateur ?. Le chemin de la ressource correspond au segment de l'URL situé entre l'hôte et la chaîne de requête ; il commence toujours par /. En l'absence de chaîne de requête, utilisez uniquement le chemin de la ressource.

Exemple :

/llm-p2e4XXXXXXXXsvtn/datacenter/category

Étape 3 : Construire la chaîne à signer

Élaborez la chaîne à signer (stringToSign) en vous basant sur ce pseudo-code :

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

Paramètre

Description

HTTPMethod

Méthode HTTP en majuscules, telle que POST ou GET.

Accept

Valeur de l'en-tête Accept. Chaîne vide si cet en-tête est absent.

ContentMD5

Valeur de l'en-tête Content-MD5. Chaîne vide si cet en-tête est absent.

ContentType

Valeur de l'en-tête Content-Type. Chaîne vide si cet en-tête est absent.

Remarque

Type MIME du RequestBody.

Date

Valeur de l'en-tête Date.

CanonicalizedHeaders

En-têtes canoniques obtenus lors de l'Étape 1 : Construire les en-têtes canoniques.

CanonicalizedResource

Ressource canonique obtenue lors de l'Étape 2 : Construire la ressource canonique.

Exemple :

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

Étape 4 : Calculer la signature

Conformément à la norme RFC2104, signez la chaîne issue de l'étape 3 à l'aide de l'algorithme HMAC-SHA1, puis encodez le résultat en Base64.

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

SigningKey correspond à votre secret AccessKey. Créez une AccessKey si vous n'en possédez pas encore.

Exemple :

s8ZMF/eAIvvPJwehLLha0bVNFJ0=

Étape 5 : Construire l'en-tête Authorization

Attribuez à l'en-tête Authorization la valeur suivante.

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

Exemple de valeur :

acs YourAccessKeyId:s8ZMF/eAIvvPJwehLLha0bVNFJ0=

Étape 6 : Ajouter la signature à la requête et envoyer celle-ci

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"}

Exemples de code pour la signature

Exemple Java

Remarque

Ce code s'exécute sur JDK 1.8. Adaptez-le à votre environnement si nécessaire.

Ajoutez les dépendances Maven suivantes à votre fichier 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());
        }
    }
}

Références

Différencier les styles ROA et RPC.