Signature mechanism
To ensure the security of API calls, Alibaba Cloud uses a signature to verify the identity of each API request. All API requests, whether sent over HTTP or HTTPS, must include signature information. This topic describes how to calculate a signature and provides code examples in Java, Python, and Go.
Overview
For RPC API calls, add a signature to the query of the API request in the following format.
https://Endpoint/?SignatureVersion=1.0&SignatureMethod=HMAC-SHA1&SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&Signature=CT9X0VtwR86fNWSnsc6v8YGOjuE%3D&The parameters are described as follows:
SignatureMethod: The signature method. Only HMAC-SHA1 is supported.
SignatureVersion: The version of the signature algorithm. The current version is 1.0.
SignatureNonce: A unique random number used to prevent replay attacks. You must use a different random value for each request. We recommend that you use a universally unique identifier (UUID).
Signature: The signature string generated by symmetrically encrypting the request string using your AccessKey secret.
The signature algorithm complies with the RFC 2104 HMAC-SHA1 specification. It uses your AccessKey secret to calculate the HMAC value of the encoded and sorted request string. The signature is calculated based on the request parameters. Because the content of each API request is different, the generated signature is also different. Follow the steps in this topic to calculate the signature. For more information about the signature rules, see Signature mechanism.
String signature = Base64(HMAC_SHA1(AccessSecret + "&", UTF_8_Encoding_Of(stringToSign)))Step 1: Construct the string to be signed
Construct a canonicalized query string from the request parameters.
Sort all request parameters alphabetically by parameter name. This includes both common request parameters and API-specific parameters, but excludes the Signature parameter.
NoteThese are the parameters in the query string of the request URI. The query string is the part of the URI that follows the question mark (?) and contains parameters connected by ampersands (&). For more information, see the Example section.
URL-encode the names and values of the sorted request parameters using the UTF-8 character set. The encoding rules are described in the following table.
Character
Encoding method
A-Z, a-z, 0-9, and the characters -, _, ., and ~
Are not encoded.
Other characters
Are encoded in the %XY format, where XY is the hexadecimal representation of the character's ASCII code. For example, a double quotation mark (") is encoded as %22.
Extended UTF-8 characters
Are encoded in the %XY%ZA... format.
A space
Is encoded as %20, not a plus sign (+).
Note: This encoding method is different from the standard application/x-www-form-urlencoded encoding algorithm of Multipurpose Internet Mail Extensions (MIME), such as the algorithm implemented in Java's java.net.URLEncoder standard library. You can first encode the string using a standard library, and then replace plus signs (+) with %20, asterisks (*) with %2A, and %7E with tildes (~) to obtain the required encoded string. This algorithm can be implemented using the following percentEncode method:
private static String percentEncode(String value) throws UnsupportedEncodingException { return value != null ? URLEncoder.encode(value, "UTF-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~") : null; }Connect the encoded parameter name and its value with an equal sign (=).
Connect the parameter pairs from the previous step with ampersands (&) in the order established in Step 1.a. This creates the canonicalized query string.
Use the canonicalized query string from Step 1 to construct the string to be signed based on the following rules.
String StringToSign = HTTPMethod + "&" + percentEncode("/") + "&" + percentEncode(CanonicalizedQueryString)Where:
HttpMethod is the HTTP method used to send the request, such as GET. Note: If you use the GET method to calculate the signature, you must also use the GET method to send the final request. Otherwise, a signature error occurs.
percentEncode("/") is the value obtained by encoding the forward slash character (/), which is %2F.
percentEncode(CanonicalizedQueryString) is the string obtained by encoding the canonicalized query string from Step 1 based on the encoding rules described in Step 1.b.
Step 2: Calculate the signature value
Calculate the HMAC value of the string to be signed (StringToSign) as defined in RFC 2104.
NoteThe key used for the calculation is your AccessKey secret appended with an ampersand (&) character (ASCII code 38). The hash algorithm is SHA1.
Base64-encode the HMAC value to obtain the signature string (Signature).
Add the generated signature to the request parameters as the Signature parameter.
NoteWhen you send the signature as the final request parameter, it must be URL-encoded in compliance with RFC 3986.
Example
This example uses the DescribeRegions API. Assume that the AccessKey ID is testid and the AccessKey secret is testsecret. The request URL before it is signed is as follows:
http://ecs.aliyuncs.com/?Timestamp=2016-02-23T12:46:24Z&Format=XML&AccessKeyId=testid&Action=DescribeRegions&SignatureMethod=HMAC-SHA1&SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&Version=2014-05-26&SignatureVersion=1.0The request parameters sorted alphabetically by name are as follows:
AccessKeyId=testid&Action=DescribeRegions&Format=XML&SignatureMethod=HMAC-SHA1&SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&SignatureVersion=1.0&Timestamp=2016-02-23T12:46:24Z&Version=2014-05-26As described in Step 1, after the names and values of the sorted request parameters are URL-encoded using the UTF-8 character set, the result is as follows:
AccessKeyId=testid&Action=DescribeRegions&Format=XML&SignatureMethod=HMAC-SHA1&SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&SignatureVersion=1.0&Timestamp=2016-02-23T12%3A46%3A24Z&Version=2014-05-26As described in Part 2 of Step 1, the string to sign (stringToSign) for the GET method is as follows:
GET&%2F&AccessKeyId%3Dtestid%26Action%3DDescribeRegions%26Format%3DXML%26SignatureMethod%3DHMAC-SHA1%26SignatureNonce%3D3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf%26SignatureVersion%3D1.0%26Timestamp%3D2016-02-23T12%253A46%253A24Z%26Version%3D2014-05-26The signature (Signature) that is obtained using the method in Step 2 is as follows:
OLeaidS1JvxuMvnyHOwuJ+uX5qY=Finally, add the RFC 3986-encoded signature (Signature) parameter to the request URL. The final URL is as follows:
http://ecs.aliyuncs.com/?Timestamp=2016-02-23T12:46:24Z&Format=XML&AccessKeyId=testid&Action=DescribeRegions&SignatureMethod=HMAC-SHA1&SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&Version=2014-05-26&SignatureVersion=1.0&Signature=OLeaidS1JvxuMvnyHOwuJ%2BuX5qY%3DCode examples
You can refer to the following code examples to construct the final request URL. You do not need to install any third-party libraries.
The following code is for demonstration purposes only. Do not use this code in a production environment.
package demo;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
import java.time.temporal.ChronoField;
import java.util.Arrays;
import java.util.Base64;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
public class Demo {
private static String percentEncode(String value) {
try {
return value != null ? URLEncoder.encode(value, "UTF-8")
.replace("+", "%20")
.replace("*", "%2A")
.replace("%7E", "~") : null;
} catch (UnsupportedEncodingException ignore) {
return value;
}
}
private static String urlDecode(String value) {
try {
return URLDecoder.decode(value, "UTF-8");
} catch (UnsupportedEncodingException ignore) {
return value;
}
}
private static String readFromInputStream(InputStream source) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(source))) {
return reader.lines().collect(Collectors.joining("\n"));
} catch (IOException ignore) {
return "";
}
}
private static String doPost(String url, String fileName) {
HttpURLConnection urlConnection = null;
try {
URL postUrl = new URL(url);
urlConnection = (HttpURLConnection) postUrl.openConnection();
urlConnection.setDoOutput(true);
urlConnection.setDoInput(true);
urlConnection.setRequestMethod("POST");
urlConnection.setUseCaches(false);
urlConnection.setRequestProperty("Content-Type", "application/octet-stream");
Path filePath = Paths.get(fileName);
if (!filePath.toFile().isFile()) {
throw new FileNotFoundException(String.format("file:%s not found", fileName));
}
Files.copy(filePath, urlConnection.getOutputStream());
return readFromInputStream(urlConnection.getInputStream());
} catch (FileNotFoundException e) {
return e.getMessage();
} catch (IOException e) {
if (urlConnection != null) {
return readFromInputStream(urlConnection.getErrorStream());
}
return e.getMessage();
}
}
private static String doGet(String url) {
HttpURLConnection urlConnection = null;
try {
URL postUrl = new URL(url);
urlConnection = (HttpURLConnection) postUrl.openConnection();
urlConnection.setDoOutput(true);
urlConnection.setDoInput(true);
urlConnection.setRequestMethod("GET");
urlConnection.setUseCaches(false);
return readFromInputStream(urlConnection.getInputStream());
} catch (IOException e) {
if (urlConnection != null) {
return readFromInputStream(urlConnection.getErrorStream());
}
return e.getMessage();
}
}
public static String getSignature(String url, String secret, String httpMethod) throws Exception {
// Parse the query string from the URL.
URL u = new URL(url);
String query = u.getQuery();
// Get the canonicalized query string.
String canonicalString = Arrays.stream(query.split("&"))
.map(s -> s.split("="))
// Remove invalid empty parameters (for example, https://example?Url=&AccessKeyId=).
.filter(arr -> arr != null && arr.length > 1)
// Sort the request parameters alphabetically.
.sorted(Comparator.comparing(arr -> arr[0]))
// Encode parameter names and values according to RFC 3986.
.map(arr -> String.format("%s=%s", percentEncode(arr[0]), percentEncode(urlDecode(arr[1]))))
// Join the encoded parameters with "&".
.reduce((s1, s2) -> s1 + "&" + s2)
.orElse("");
// Construct the string to be signed from the canonicalized query string.
String stringToSign = httpMethod + "&" + percentEncode("/") + "&" + percentEncode(canonicalString);
// Append "&" to the AccessKeySecret to form the key for the HMAC-SHA1 algorithm.
secret += "&";
// The HMAC-SHA1 encoded bytes.
SecretKey secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(secretKey);
byte[] hashBytes = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
// Generate the final signature string according to Base64 encoding rules.
String signature = Base64.getEncoder().encodeToString(hashBytes);
return signature;
}
/**
* Get common request parameters. For more information about common request parameters, see https://help.aliyun.com/document_detail/145074.html
*
* @param accessKeyId Your AccessKey ID. For information about how to obtain an AccessKey ID, see https://help.aliyun.com/document_detail/116401.htm?spm=a2c4g.11186623.0.0.6e6027b5fXEVz0
* @return A map of common request parameters.
*/
private static Map<String, String> getCommonParameters(String accessKeyId) {
return new HashMap<String, String>() {
{
put("Action", "RecognizeGeneral"); // The name of the API to call. This example uses RecognizeGeneral.
put("Version", "2021-07-07"); // The API version. The value is fixed to 2021-07-07 for OCR.
put("Format", "JSON"); // The format of the response. Valid values: JSON and XML.
put("AccessKeyId", accessKeyId); // Your AccessKey ID.
put("SignatureNonce", UUID.randomUUID().toString()); // A unique random number for the signature. It must be unique for each call.
put("Timestamp", Instant.now().with(ChronoField.NANO_OF_SECOND, 0).toString()); // Requires Java 8 or later. If you are using an earlier version of Java, use a different method to get the timestamp.
put("SignatureMethod", "HMAC-SHA1"); // The signature method. The value is fixed to HMAC-SHA1.
put("SignatureVersion", "1.0"); // The signature version. The value is fixed to 1.0.
}
};
}
/**
* Example of calling an API by passing an image URL. This example uses the RecognizeGeneral API.
*/
private static void getDemo() throws Exception {
String endpoint = "ocr-api.cn-hangzhou.aliyuncs.com";
// For information about how to obtain an AccessKey ID and AccessKey secret, see the documentation: https://help.aliyun.com/document_detail/116401.htm?spm=a2c4g.11186623.0.0.6e6027b5GvMJ25
String accessKeyId = "";
String accessKeySecret = "";
// Get common request parameters.
Map<String, String> parametersMap = getCommonParameters(accessKeyId);
// Add business parameters. The parameters vary by API. This example uses RecognizeGeneral, where the Url parameter is the image URL.
parametersMap.put("Url", "https://example.png");
// Initialize the request URL.
StringBuilder urlBuilder = new StringBuilder("https://" + endpoint + "/?");
// Append the business parameters to the request URL.
for (Map.Entry<String, String> entry : parametersMap.entrySet()) {
// entry.getValue() may contain characters like "&". It needs to be encoded.
urlBuilder.append(String.format("%s=%s", entry.getKey(), URLEncoder.encode(entry.getValue(), "UTF-8")))
.append('&');
}
// Remove the trailing "&".
String url = urlBuilder.substring(0, urlBuilder.length() - 1);
// Get the signature.
String signature = getSignature(url, accessKeySecret, "GET");
// Encode the signature according to RFC 3986 and append it to the final request URL.
url += String.format("&Signature=%s", percentEncode(signature));
// Call the API using the GET method and print the recognition result. This example uses RecognizeGeneral.
String result = doGet(url);
System.out.println(result);
}
/**
* Example of recognizing a local file. This example uses the RecognizeGeneral API.
*/
private static void postDemo() throws Exception {
String endpoint = "ocr-api.cn-hangzhou.aliyuncs.com";
// For information about how to obtain an AccessKey ID and AccessKey secret, see the documentation: https://help.aliyun.com/document_detail/116401.htm?spm=a2c4g.11186623.0.0.6e6027b5GvMJ25
String accessKeyId = "";
String accessKeySecret = "";
// Get common request parameters.
Map<String, String> parametersMap = getCommonParameters(accessKeyId);
// Initialize the request URL.
StringBuilder urlBuilder = new StringBuilder("https://" + endpoint + "/?");
// Append the business parameters to the request URL.
for (Map.Entry<String, String> entry : parametersMap.entrySet()) {
// entry.getValue() may contain characters like "&". It needs to be encoded.
urlBuilder.append(String.format("%s=%s", entry.getKey(), URLEncoder.encode(entry.getValue(), "UTF-8")))
.append('&');
}
// Remove the trailing "&".
String url = urlBuilder.substring(0, urlBuilder.length() - 1);
// Get the signature.
String signature = getSignature(url, accessKeySecret, "POST");
// Encode the signature according to RFC 3986 and append it to the final request URL.
url += String.format("&Signature=%s", percentEncode(signature));
// The local file.
String fileName = "/home/example.png";
// Call the API using the POST method and print the recognition result. This example uses RecognizeGeneral.
String result = doPost(url, fileName);
System.out.println(result);
}
public static void main(String[] args) throws Exception {
// getDemo();
// postDemo();
}
}
try:
from urllib.parse import quote, urlparse, parse_qs
except:
from urllib import quote
from urlparse import urlparse, parse_qs
import hmac
import base64
import hashlib
import uuid
from datetime import datetime, tzinfo, timedelta
class UTC(tzinfo):
"""Represents UTC time.
"""
def tzname(self, dt):
return "UTC"
def utcoffset(self, dt):
return timedelta(0)
def dst(self, dt):
return timedelta(0)
def percentEncode(s):
return quote(s.encode('utf-8'), safe='~')
def get_signature(url, secret, http_method):
# Parse the query string from the URL.
queries = parse_qs(urlparse(url).query)
# Sort the request parameters alphabetically.
keys = sorted(queries.keys())
# Initialize the canonicalized query string.
canonicalized_query_string = ""
# Generate the canonicalized query string.
for k in keys:
# Encode the parameter name according to RFC 3986.
quoted_param = percentEncode(k)
# Encode the parameter value according to RFC 3986.
quoted_value = percentEncode(queries[k][0])
# Connect the encoded parameter name and value with an equal sign (=), and then join them with "&".
canonicalized_query_string += '&%s=%s' % (quoted_param, quoted_value)
# Remove the leading "&".
canonicalized_query_string = canonicalized_query_string[1:]
# Construct the string to be signed from the canonicalized query string.
string_to_sign = http_method + '&' + percentEncode('/') + '&' + percentEncode(canonicalized_query_string)
# Append "&" to the AccessKeySecret to form the key for the HMAC-SHA1 algorithm.
secret += '&'
# The HMAC-SHA1 encoded bytes.
hash_bytes = hmac.new(secret.encode('utf-8'), string_to_sign.encode('utf-8'), digestmod=hashlib.sha1).digest()
# Generate the final signature string according to Base64 encoding rules.
signature = base64.b64encode(hash_bytes).decode('utf-8')
return signature
def get_common_parameters(access_key_id):
"""Get common request parameters. For more information about common request parameters, see https://help.aliyun.com/document_detail/145074.html
Args:
Your AccessKey ID. For information about how to obtain an AccessKey ID, see https://help.aliyun.com/document_detail/116401.htm?spm=a2c4g.11186623.0.0.6e6027b5fXEVz0
Returns:
A dictionary of common request parameters.
"""
return {
"Action": "RecognizeGeneral", # The name of the API to call. This example uses RecognizeGeneral.
"Version": "2021-07-07", # The API version. The value is fixed to 2021-07-07 for OCR.
"Format": "JSON", # The format of the response. Valid values: JSON and XML.
"AccessKeyId": access_key_id, # Your AccessKey ID.
"SignatureNonce": uuid.uuid4(), # A unique random number for the signature.
"Timestamp": datetime.utcnow().replace(tzinfo=UTC()).strftime('%Y-%m-%dT%H:%M:%SZ'), # The request timestamp. It must be in ISO 8601 format and use UTC. The format is yyyy-MM-ddTHH:mm:ssZ.
"SignatureMethod": "HMAC-SHA1", # The signature method. The value is fixed to HMAC-SHA1.
"SignatureVersion": "1.0" # The signature version. The value is fixed to 1.0.
}
def get_request_url():
"""Get the complete request URL.
"""
endpoint = "ocr-api.cn-hangzhou.aliyuncs.com"
# For information about how to obtain an AccessKey ID and AccessKey secret, see the documentation: https://help.aliyun.com/document_detail/116401.htm?spm=a2c4g.11186623.0.0.6e6027b5GvMJ25
access_key_id = "" # Your AccessKey ID.
access_key_secret = "" # Your AccessKey secret.
# Get common request parameters.
parameters = get_common_parameters(access_key_id)
# Add business parameters. The parameters vary by API. This example uses RecognizeGeneral, where the Url parameter is the image URL.
parameters['Url'] = "https://example.png"
# Append the business parameters to the request URL.
url = "https://%s/?%s" % (endpoint, '&'.join('%s=%s' % (k, v) for k, v in parameters.items()))
# Get the signature (GET method).
signature = get_signature(url, access_key_secret, 'GET')
# Encode the signature according to RFC 3986 and append it to the final request URL.
url += "&Signature=" + percentEncode(signature)
return url
if __name__ == '__main__':
request_url = get_request_url()
print(request_url)
package main
import (
"crypto/hmac"
"crypto/rand"
"crypto/sha1"
"encoding/base64"
"fmt"
"net/url"
"sort"
"strings"
"time"
)
// uuid generates a random string to be used as SignatureNonce.
func uuid() string {
b := make([]byte, 16)
_, err := rand.Read(b)
if err != nil {
panic(err)
}
return fmt.Sprintf("%X-%X-%X-%X-%X", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
}
func percentEncode(s string) string {
s = url.QueryEscape(s)
s = strings.ReplaceAll(s, "+", "%20")
s = strings.ReplaceAll(s, "*", "%2A")
s = strings.ReplaceAll(s, "%7E", "~")
return s
}
// getCommonParameters gets common request parameters. For more information about common request parameters, see https://help.aliyun.com/document_detail/145074.html
func getCommonParameters(accessKeyId string) map[string]string {
return map[string]string{
"Action": "RecognizeGeneral", // The name of the API to call. This example uses RecognizeGeneral.
"Version": "2021-07-07", // The API version. The value is fixed to 2021-07-07 for OCR.
"Format": "JSON", // The format of the response. Valid values: JSON and XML.
"AccessKeyId": accessKeyId, // Your AccessKey ID.
"SignatureNonce": uuid(), // A unique random number for the signature.
"Timestamp": time.Now().UTC().Format("2006-01-02T15:04:05.000Z"), // The request timestamp. It must be in ISO 8601 format and use UTC. The format is yyyy-MM-ddTHH:mm:ssZ. For example, 2018-01-01T12:00:00Z represents 20:00:00 on January 1, 2018 (UTC+8).
"SignatureMethod": "HMAC-SHA1", // The signature method. The value is fixed to HMAC-SHA1.
"SignatureVersion": "1.0", // The signature version. The value is fixed to 1.0.
}
}
// getSignature gets the signature.
func getSignature(urlString, secret, httpMethod string) string {
// Parse the query string from the URL.
u, err := url.Parse(urlString)
if err != nil {
panic(err)
}
rawQuery := u.RawQuery
// Record the request parameter names from the URL into a slice.
queryMap, err := url.ParseQuery(rawQuery)
if err != nil {
panic(err)
}
keys := make([]string, 0)
for k := range queryMap {
keys = append(keys, k)
}
// Sort the request parameters alphabetically.
sort.Strings(keys)
// Initialize the canonicalized query string.
canonicalString := ""
for i, k := range keys {
canonicalString += fmt.Sprintf("%s=%s", percentEncode(k), percentEncode(queryMap[k][0]))
if i < len(keys)-1 {
canonicalString += "&"
}
}
// Construct the string to be signed from the canonicalized query string.
stringToSign := httpMethod + "&" + percentEncode("/") + "&" + percentEncode(canonicalString)
// Append "&" to the AccessKeySecret to form the key for the HMAC-SHA1 algorithm.
secret += "&"
// The HMAC-SHA1 encoded bytes.
h := hmac.New(sha1.New, []byte(secret))
_, err = h.Write([]byte(stringToSign))
if err != nil {
panic(err)
}
b := h.Sum(nil)
// Generate the final signature string according to Base64 encoding rules.
signature := base64.StdEncoding.EncodeToString(b)
return signature
}
// getRequestUrl gets the complete request URL.
func getRequestUrl() string {
endpoint := "ocr-api.cn-hangzhou.aliyuncs.com"
// For information about how to obtain an AccessKey ID and AccessKey secret, see the documentation: https://help.aliyun.com/document_detail/116401.htm?spm=a2c4g.11186623.0.0.6e6027b5GvMJ25
accessKeyId := "" // Your AccessKey ID.
accessKeySecret := "" // Your AccessKey secret.
// Get common request parameters.
parameters := getCommonParameters(accessKeyId)
// Add business parameters. The parameters vary by API. This example uses RecognizeGeneral, where the Url parameter is the image URL.
parameters["Url"] = "https://example.png"
// Append the business parameters to the request URL.
url := "https://" + endpoint + "/?"
for k, v := range parameters {
url += fmt.Sprintf("%s=%s&", k, v)
}
// Remove the trailing "&" from the URL.
url = url[:len(url)-1]
// Get the signature.
signature := getSignature(url, accessKeySecret, "GET")
// Encode the signature according to RFC 3986 and append it to the final request URL.
url += "&Signature=" + percentEncode(signature)
return url
}
func main() {
url := getRequestUrl()
fmt.Println(url)
}
const url = require("url");
const crypto = require("crypto");
const percentEncode = (s) => {
return encodeURIComponent(s)
.replace(/\+/g, "%20")
.replace(/\*/g, "%2A")
.replace(/%7E/g, "~");
};
// Get common request parameters. For more information about common request parameters, see https://help.aliyun.com/document_detail/145074.html
const getCommonParameters = (accessKeyId) => {
return {
Action: "RecognizeGeneral", // The name of the API to call. This example uses RecognizeGeneral.
Version: "2021-07-07", // The API version. The value is fixed to 2021-07-07 for OCR.
Format: "JSON", // The format of the response. Valid values: JSON and XML.
AccessKeyId: accessKeyId, // Your AccessKey ID.
SignatureNonce: crypto.randomBytes(16).toString("hex"), // A unique random number for the signature.
Timestamp: new Date().toISOString(), // The request timestamp. It must be in ISO 8601 format and use UTC. The format is yyyy-MM-ddTHH:mm:ssZ.
SignatureMethod: "HMAC-SHA1", // The signature method. The value is fixed to HMAC-SHA1.
SignatureVersion: "1.0", // The signature version. The value is fixed to 1.0.
};
};
// Get the signature.
const getSignature = (urlString, secret, httpMethod) => {
// Parse the query string from the URL.
const query = url.parse(urlString, true).query;
// Sort the request parameters alphabetically.
keys = Object.keys(query).sort();
// Initialize the canonicalized query string.
canonicalString = "";
for (const k of keys) {
// Encode the parameter name according to RFC 3986.
let encodedParam = percentEncode(k);
// Encode the parameter value according to RFC 3986.
let encodedValue = percentEncode(query[k]);
// Connect the encoded parameter name and value with an equal sign (=), and then join them with "&".
canonicalString += `&${encodedParam}=${encodedValue}`;
}
// Remove the leading "&".
canonicalString = canonicalString.substring(1);
// Construct the string to be signed from the canonicalized query string.
let stringToSign =
httpMethod +
"&" +
percentEncode("/") +
"&" +
percentEncode(canonicalString);
// Append "&" to the AccessKeySecret to form the key for the HMAC-SHA1 algorithm.
secret += "&";
// The HMAC-SHA1 encoded bytes.
let res = crypto.createHmac("sha1", secret).update(stringToSign).digest();
// Generate the final signature string according to Base64 encoding rules.
let signature = res.toString("base64");
return signature;
};
// Get the complete request URL.
const getRequestUrl = () => {
const endpoint = "ocr-api.cn-hangzhou.aliyuncs.com";
// For information about how to obtain an AccessKey ID and AccessKey secret, see the documentation: https://help.aliyun.com/document_detail/116401.htm?spm=a2c4g.11186623.0.0.6e6027b5GvMJ25
const accessKeyId = ""; // Your AccessKey ID.
const accessKeySecret = ""; // Your AccessKey secret.
// Get common request parameters.
let parameters = getCommonParameters(accessKeyId);
// Add business parameters. The parameters vary by API. This example uses RecognizeGeneral, where the Url parameter is the image URL.
parameters["Url"] = "https://example.png";
// Append the business parameters to the request URL.
let requestUrl = `https://${endpoint}/?`;
for (const key in parameters) {
requestUrl += `${key}=${parameters[key]}&`;
}
requestUrl = requestUrl.substring(0, requestUrl.length - 1);
// Get the signature.
const signature = getSignature(requestUrl, accessKeySecret, "GET");
// Encode the signature according to RFC 3986 and append it to the final request URL.
requestUrl += `&Signature=${percentEncode(signature)}`;
return requestUrl;
};
const res = getRequestUrl();
console.log(res);