Adobe Experience Manager Assets開發人員使用案例、API和參考資料 assets-cloud-service-apis

文章包含Assets開發人員的建議、參考資料和資源,以Cloud Service形式提供。 其中包含新的資產上傳模組、API參考資料,以及有關後處理工作流程中所提供支援的資訊。

Experience Manager Assets API與作業 use-cases-and-apis

Assets as a Cloud Service提供數個API,以程式設計方式與數位資產互動。 每個API都支援特定使用案例,如下表所述。 Assets使用者介面、Experience Manager案頭應用程式和Adobe Asset Link支援所有或部分作業。

CAUTION
有些API持續存在,但未主動支援(以×表示)。 請儘量不要使用這些API。
支援等級
說明
支援
×
不支援。 請勿使用。
-
無法使用
使用案例
aem-upload
Experience Manager/ Sling / JCR Java API
Asset compute服務
Assets HTTP API
Sling GET / POST servlet
GraphQL
原始二進位檔
建立原始檔案
×
-
×
×
-
讀取原始檔案
-
×
-
更新原始檔案
×
×
×
-
刪除原始檔案
-
-
-
複製原始檔案
-
-
-
移動原始檔案
-
-
-
中繼資料
建立中繼資料
-
-
讀取中繼資料
-
-
-
更新中繼資料
-
-
刪除中繼資料
-
-
複製中繼資料
-
-
-
移動中繼資料
-
-
-
內容片段(CF)
建立CF
-
-
-
-
讀取CF
-
-
-
更新CF
-
-
-
-
刪除CF
-
-
-
-
複製CF
-
-
-
-
移動CF
-
-
-
-
版本
建立版本
-
-
-
-
讀取版本
-
-
-
-
-
刪除版本
-
-
-
-
-
資料夾
建立資料夾
-
-
-
讀取資料夾
-
-
-
-
刪除資料夾
-
-
-
複製資料夾
-
-
-
行動資料夾
-
-
-

資產上傳 asset-upload

在Experience Manager中以Cloud Service身分,您可以使用HTTP API直接將資產上傳到雲端儲存空間。 上傳二進位檔案的步驟如下。 在外部應用程式中執行這些步驟,而不是在Experience Manager JVM中執行。

  1. 提交HTTP要求。 它會通知Experience Manager部署您打算上傳新的二進位檔。
  2. 將二進位檔的內容PUT到起始要求提供的一或多個URI。
  3. 提交HTTP要求,通知伺服器已成功上傳二進位檔的內容。

直接二進位上傳通訊協定概觀

IMPORTANT
在外部應用程式中而不是在Experience Manager JVM中執行上述步驟。

方法提供可擴充且效能更高的資產上傳處理方式。 與Experience Manager 6.5的差異如下:

  • 二進位檔不會通過Experience Manager,現在只是協調上傳程式與為部署設定的二進位雲端儲存空間。
  • 二進位雲端儲存空間可與內容傳遞網路(CDN)或Edge網路搭配使用。 CDN會選取較接近使用者端的上傳端點。 當資料傳輸至附近端點的距離較短時,上傳效能和使用者體驗會改善,尤其是對於分散各地的團隊。
NOTE
檢視使用者端代碼,以在開放原始碼aem-upload程式庫中實作此方法。
IMPORTANT
在某些情況下,由於Experience Manager中儲存的最終一致性性質,變更可能不會在Cloud Service請求之間完全傳播。 這會導致404個起始或完成上傳呼叫的回應,因為必要的資料夾建立未傳播。 使用者端應該會收到404個回應,並透過實作附有後退策略的重試來處理這些回應。

啟動上傳 initiate-upload

將HTTPPOST請求提交到所需的資料夾。 在此資料夾中建立或更新Assets。 包含選擇器.initiateUpload.json,以表示要求將啟動二進位檔案的上傳。 例如,應建立資產的資料夾路徑為/assets/folder。 POST要求是POST https://[aem_server]:[port]/content/dam/assets/folder.initiateUpload.json

要求內文的內容型別應為application/x-www-form-urlencoded表單資料,包含下列欄位:

  • (string) fileName:必要。 資產在Experience Manager中顯示的名稱。
  • (number) fileSize:必要。 上傳資產的檔案大小(位元組)。

只要每個二進位檔案都包含必要欄位,就可以使用單一要求來起始多個二進位檔案的上傳。 如果成功,請求會以下列格式回應201狀態代碼和包含JSON資料的內文:

{
    "completeURI": "(string)",
    "folderPath": "(string)",
    "files": [
        {
            "fileName": "(string)",
            "mimeType": "(string)",
            "uploadToken": "(string)",
            "uploadURIs": [
                "(string)"
            ],
            "minPartSize": (number),
            "maxPartSize": (number)
        }
    ]
}
  • completeURI (字串):當二進位檔完成上傳時,呼叫此URI。 URI可以是絕對URI或相對URI,使用者端應該能夠處理任一個。 也就是說,值可以是"https://[aem_server]:[port]/content/dam.completeUpload.json""/content/dam.completeUpload.json"請參閱完成上傳
  • folderPath (字串):上傳二進位檔的資料夾完整路徑。
  • (files) (陣列):元素清單,其長度和順序符合起始要求中提供的二進位資訊清單長度和順序。
  • fileName (字串):起始要求中提供的對應二進位檔名稱。 此值應包含在完整請求中。
  • mimeType (字串):起始要求中提供的對應二進位檔的mime型別。 此值應包含在完整請求中。
  • uploadToken (字串):對應二進位檔的上傳權杖。 此值應包含在完整請求中。
  • uploadURIs (陣列):字串清單,其值是二進位內容應上傳到的完整URI (請參閱上傳二進位檔案)。
  • minPartSize (數字):如果有多個URI,可以提供給任一uploadURIs之資料的最小長度(位元組)。
  • maxPartSize (數字):如果有多個URI,可提供給uploadURIs之任一方的最大資料長度(位元組)。

上傳二進位檔 upload-binary

起始上傳的輸出包含一或多個上傳URI值。 如果提供了多個URI,使用者端可以依序將二進位分割成多個部分,並向提供的上傳URI提出每個部分的PUT請求。 如果您選擇將二進位檔案分割成零件,請遵循下列准則:

  • 除了最後一個零件外,每個零件的大小必須大於或等於minPartSize
  • 每個部分的大小必須小於或等於maxPartSize
  • 如果二進位檔的大小超過maxPartSize,請將二進位檔分割成多個部分以上傳。
  • 您不需要使用所有URI。

如果您的二進位檔大小小於或等於maxPartSize,您可以改為將整個二進位檔上傳至單一上傳URI。 如果提供了多個上傳URI,請使用第一個並忽略其餘的URI。 您不需要使用所有URI。

CDN邊緣節點有助於加速要求的二進位檔上傳。

最簡單的方法是使用maxPartSize的值做為零件大小。 如果您使用此值作為部分大小,API合約可確保有足夠的上傳URI來上傳您的二進位檔。 若要這麼做,請依序將二進位檔案分割成大小為maxPartSize的部分,每個部分使用一個URI。 最後部分的大小可小於或等於maxPartSize。 例如,假設二進位檔案的總大小為20,000個位元組,minPartSize為5,000個位元組,maxPartSize為8,000個位元組,而且上傳URI的數量為5。 執行以下步驟:

  • 使用第一個上傳URI上傳二進位的前8,000個位元組。
  • 使用第二個上傳URI上傳二進位檔案的第二個8,000位元組。
  • 使用第三個上傳URI上傳二進位檔案的最後4,000個位元組。 因為這是最後部分,所以它不需要大於minPartSize
  • 您不需要使用最後兩個上傳URI。 您可以忽略它們。

常見的錯誤是根據API提供的上傳URI數量來計算零件大小。 API合約無法保證此方法可正常運作,而且可能會造成零件大小超出minPartSizemaxPartSize的範圍。 這可能會造成二進位上傳失敗。

同樣地,最簡單且最安全的方式是隻使用大小等於maxPartSize的部分。

如果上傳成功,伺服器會以201狀態代碼回應每個要求。

NOTE
如需上傳演演算法的詳細資訊,請參閱Apache Jackrabbit Oak專案中的正式功能檔案API檔案

完成上傳 complete-upload

上傳二進位檔案的所有部分後,將HTTPPOST請求提交至初始化資料提供的完整URI。 要求內文的內容型別應為application/x-www-form-urlencoded表單資料,包含下列欄位。

欄位
類型
必要與否
說明
fileName
字串
必填
由初始資料提供的資產名稱。
mimeType
字串
必填
由起始資料提供的二進位檔的HTTP內容型別。
uploadToken
字串
必填
上傳二進位的Token,如初始化資料所提供。
createVersion
布林值
選用
如果True和指定名稱的資產存在,則Experience Manager會建立該資產的新版本。
versionLabel
字串
選用
如果建立新版本,則會提供與資產新版本相關聯的標籤。
versionComment
字串
選用
如果建立了新版本,註釋會與該版本相關聯。
replace
布林值
選用
如果True和指定名稱的資產存在,Experience Manager會刪除該資產,然後重新建立它。
uploadDuration
數字
選用
檔案完整上傳的總時間,以毫秒為單位。 如果指定,上傳持續時間會包含在系統的記錄檔中,以進行傳輸率分析。
fileSize
數字
選用
檔案的大小(位元組)。 如果指定,檔案大小會包含在系統的記錄檔中,以進行傳輸速率分析。
NOTE
如果資產存在,且既未指定createVersion也未指定replace,則Experience Manager會以新的二進位檔更新資產的目前版本。

如同起始程式,完整的請求資料可能包含多個檔案的資訊。

在呼叫檔案的完整URL之前,不會完成上傳二進位檔的程式。 資產會在上傳程式完成後處理。 即使資產的二進位檔案已完全上傳,但上傳程式未完成,處理作業也不會開始。 如果上傳成功,伺服器會以200狀態碼回應。

將資產上傳至AEM as a Cloud Service的範例殼層指令碼 upload-assets-shell-script

AEM as a Cloud Service中直接二進位存取的多步驟上傳程式如下範例殼層指令碼aem-upload.sh所示:

#!/bin/bash

# Check if pv is installed
if ! command -v pv &> /dev/null; then
    echo "Error: 'pv' command not found. Please install it before running the script."
    exit 1
fi

# Check if jq is installed
if ! command -v jq &> /dev/null; then
    echo "Error: 'jq' command not found. Please install it before running the script."
    exit 1
fi

# Set DEBUG to true to enable debug statements
DEBUG=true

# Function for printing debug statements
function debug() {
    if [ "${DEBUG}" = true ]; then
        echo "[DEBUG] $1"
    fi
}

# Function to check if a file exists
function file_exists() {
    [ -e "$1" ]
}

# Function to check if a path is a directory
function is_directory() {
    [ -d "$1" ]
}

# Check if the required number of parameters are provided
if [ "$#" -ne 4 ]; then
    echo "Usage: $0 <aem-url> <asset-folder> <file-to-upload> <bearer-token>"
    exit 1
fi

AEM_URL="$1"
ASSET_FOLDER="$2"
FILE_TO_UPLOAD="$3"
BEARER_TOKEN="$4"

# Extracting file name or folder name from the file path
NAME=$(basename "${FILE_TO_UPLOAD}")

# Step 1: Check if "file-to-upload" is a folder
if is_directory "${FILE_TO_UPLOAD}"; then
    echo "Uploading files from the folder recursively..."

    # Recursively upload files in the folder
    find "${FILE_TO_UPLOAD}" -type f | while read -r FILE_PATH; do
        FILE_NAME=$(basename "${FILE_PATH}")
        debug "Uploading file: ${FILE_PATH}"

        # You can choose to initiate upload for each file here
        # For simplicity, let's assume you use the same ASSET_FOLDER for all files
        ./aem-upload.sh "${AEM_URL}" "${ASSET_FOLDER}" "${FILE_PATH}" "${BEARER_TOKEN}"
    done
else
    # "file-to-upload" is a single file
    FILE_NAME="${NAME}"

    # Step 2: Calculate File Size
    FILE_SIZE=$(stat -c %s "${FILE_TO_UPLOAD}")

    # Step 3: Initiate Upload
    INITIATE_UPLOAD_ENDPOINT="${AEM_URL}/content/dam/${ASSET_FOLDER}.initiateUpload.json"

    debug "Initiating upload..."
    debug "Initiate Upload Endpoint: ${INITIATE_UPLOAD_ENDPOINT}"
    debug "File Name: ${FILE_NAME}"
    debug "File Size: ${FILE_SIZE}"

    INITIATE_UPLOAD_RESPONSE=$(curl -X POST \
        -H "Authorization: Bearer ${BEARER_TOKEN}" \
        -H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" \
        -d "fileName=${FILE_NAME}" \
        -d "fileSize=${FILE_SIZE}" \
        ${INITIATE_UPLOAD_ENDPOINT})

    # Continue with the rest of the script...
fi


# Check if the response body contains the specified HTML content for a 404 error
if echo "${INITIATE_UPLOAD_RESPONSE}" | grep -q "<title>404 Specified folder not found</title>"; then
    echo "Folder not found. Creating the folder..."

    # Attempt to create the folder
    CREATE_FOLDER_ENDPOINT="${AEM_URL}/api/assets/${ASSET_FOLDER}"

    debug "Creating folder..."
    debug "Create Folder Endpoint: ${CREATE_FOLDER_ENDPOINT}"

    CREATE_FOLDER_RESPONSE=$(curl -X POST \
        -H "Content-Type: application/json" \
        -H "Authorization: Bearer ${BEARER_TOKEN}" \
        -d '{"class":"'${ASSET_FOLDER}'","properties":{"title":"'${ASSET_FOLDER}'"}}' \
        ${CREATE_FOLDER_ENDPOINT})

    # Check the response code and inform the user accordingly
    STATUS_CODE_CREATE_FOLDER=$(echo "${CREATE_FOLDER_RESPONSE}" | jq -r '.properties."status.code"')
    case ${STATUS_CODE_CREATE_FOLDER} in
        201)
            echo "Folder created successfully. Initiating upload again..."

            # Retry Initiate Upload after creating the folder
            INITIATE_UPLOAD_RESPONSE=$(curl -X POST \
                -H "Authorization: Bearer ${BEARER_TOKEN}" \
                -H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" \
                -d "fileName=${FILE_NAME}" \
                -d "fileSize=${FILE_SIZE}" \
                ${INITIATE_UPLOAD_ENDPOINT})
            ;;
        409)
            echo "Error: Folder already exists."
            ;;
        412)
            echo "Error: Precondition failed. Root collection cannot be found or accessed."
            exit 1
            ;;
        500)
            echo "Error: Internal Server Error. Something went wrong."
            exit 1
            ;;
        *)
            echo "Error: Unexpected response code ${STATUS_CODE_CREATE_FOLDER}"
            exit 1
            ;;
    esac
fi

# Extracting values from the response
FOLDER_PATH=$(echo "${INITIATE_UPLOAD_RESPONSE}" | jq -r '.folderPath')
UPLOAD_URIS=($(echo "${INITIATE_UPLOAD_RESPONSE}" | jq -r '.files[0].uploadURIs[]'))
UPLOAD_TOKEN=$(echo "${INITIATE_UPLOAD_RESPONSE}" | jq -r '.files[0].uploadToken')
MIME_TYPE=$(echo "${INITIATE_UPLOAD_RESPONSE}" | jq -r '.files[0].mimeType')
MIN_PART_SIZE=$(echo "${INITIATE_UPLOAD_RESPONSE}" | jq -r '.files[0].minPartSize')
MAX_PART_SIZE=$(echo "${INITIATE_UPLOAD_RESPONSE}" | jq -r '.files[0].maxPartSize')
COMPLETE_URI=$(echo "${INITIATE_UPLOAD_RESPONSE}" | jq -r '.completeURI')

# Extracting "Affinity-cookie" from the response headers
AFFINITY_COOKIE=$(echo "${INITIATE_UPLOAD_RESPONSE}" | grep -i 'Affinity-cookie' | awk '{print $2}')

debug "Folder Path: ${FOLDER_PATH}"
debug "Upload Token: ${UPLOAD_TOKEN}"
debug "MIME Type: ${MIME_TYPE}"
debug "Min Part Size: ${MIN_PART_SIZE}"
debug "Max Part Size: ${MAX_PART_SIZE}"
debug "Complete URI: ${COMPLETE_URI}"
debug "Affinity Cookie: ${AFFINITY_COOKIE}"
if $DEBUG; then
    i=1
    for UPLOAD_URI in "${UPLOAD_URIS[@]}"; do
        debug "Upload URI $i: "$UPLOAD_URI
        i=$((i+1))
    done
fi


# Calculate the number of parts needed
NUM_PARTS=$(( (FILE_SIZE + MAX_PART_SIZE - 1) / MAX_PART_SIZE ))
debug "Number of Parts: $NUM_PARTS"

# Calculate the part size for the last chunk
LAST_PART_SIZE=$(( FILE_SIZE % MAX_PART_SIZE ))
if [ "${LAST_PART_SIZE}" -eq 0 ]; then
    LAST_PART_SIZE=${MAX_PART_SIZE}
fi

# Step 4: Upload binary to the blob store in parts
PART_NUMBER=1
for i in $(seq 1 $NUM_PARTS); do
    PART_SIZE=${MAX_PART_SIZE}
    if [ ${PART_NUMBER} -eq ${NUM_PARTS} ]; then
        PART_SIZE=${LAST_PART_SIZE}
        debug "Last part size: ${PART_SIZE}"
    fi

    PART_FILE="/tmp/${FILE_NAME}_part${PART_NUMBER}"

    # Creating part file
    SKIP=$((PART_NUMBER - 1))
    SKIP=$((MAX_PART_SIZE * SKIP))
    dd if="${FILE_TO_UPLOAD}" of="${PART_FILE}"  bs="${PART_SIZE}" skip="${SKIP}" count="${PART_SIZE}" iflag=skip_bytes,count_bytes  > /dev/null 2>&1
    debug "Creating part file: ${PART_FILE} with size ${PART_SIZE}, skipping first ${SKIP} bytes."


    UPLOAD_URI=${UPLOAD_URIS[$PART_NUMBER-1]}

    debug "Uploading part ${PART_NUMBER}..."
    debug "Part Size: $PART_SIZE"
    debug "Part File: ${PART_FILE}"
    debug "Part File Size: $(stat -c %s "${PART_FILE}")"
    debug "Upload URI: ${UPLOAD_URI}"

    # Upload the part in the background
    if command -v pv &> /dev/null; then
        pv "${PART_FILE}" | curl --progress-bar -X PUT --data-binary "@-" "${UPLOAD_URI}" &
    else
        curl -# -X PUT --data-binary "@${PART_FILE}" "${UPLOAD_URI}" &
    fi

    PART_NUMBER=$((PART_NUMBER + 1))
done

# Wait for all background processes to finish
wait

# Step 5: Complete the upload in AEM
COMPLETE_UPLOAD_ENDPOINT="${AEM_URL}${COMPLETE_URI}"

debug "Completing the upload..."
debug "Complete Upload Endpoint: ${COMPLETE_UPLOAD_ENDPOINT}"

RESPONSE=$(curl -X POST \
    -H "Authorization: Bearer ${BEARER_TOKEN}" \
    -H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" \
    -H "Affinity-cookie: ${AFFINITY_COOKIE}" \
    --data-urlencode "uploadToken=${UPLOAD_TOKEN}" \
    --data-urlencode "fileName=${FILE_NAME}" \
    --data-urlencode "mimeType=${MIME_TYPE}" \
    "${COMPLETE_UPLOAD_ENDPOINT}")

debug $RESPONSE

echo "File upload completed successfully."

開放原始碼上傳程式庫 open-source-upload-library

若要深入瞭解上傳演演算法,或若要建置您自己的上傳指令碼和工具,Adobe提供開放原始碼程式庫和工具:

NOTE
aem-upload程式庫和命令列工具都使用node-httptransfer程式庫

已棄用的資產上傳API deprecated-asset-upload-api

只有Adobe Experience Manager支援新的上傳方法做為Cloud Service。 來自Adobe Experience Manager 6.5的API已過時。 下列API中不建議使用與上傳或更新資產或轉譯(任何二進位上傳)相關的方法:

  • EXPERIENCE MANAGER ASSETS HTTP API
  • AssetManager Java API,例如AssetManager.createAsset(..)AssetManager.createAssetForBinary(..)AssetManager.getAssetForBinary(..)AssetManager.removeAssetForBinary(..)AssetManager.createOrUpdateAsset(..)AssetManager.createOrReplaceAsset(..)

資產處理和後續處理工作流程 post-processing-workflows

在Experience Manager中,資產處理是以使用資產微服務的​ 處理設定檔 ​組態為基礎。 處理不需要開發人員擴充功能。

若要設定後續處理工作流程,請將標準工作流程與擴充功能搭配使用,並搭配自訂步驟。

支援後處理工作流程中的工作流程步驟 post-processing-workflows-steps

如果您從舊版Experience Manager升級,則可以使用資產微服務來處理資產。 雲端原生資產微服務可更輕鬆設定和使用。 不支援舊版的DAM更新資產工作流程中所使用的幾個工作流程步驟。 如需支援類別的詳細資訊,請參閱Java API參考或Javadocs

以下技術工作流程模型已由資產微服務取代,或無法提供支援:

  • com.day.cq.dam.cameraraw.process.CameraRawHandlingProcess
  • com.day.cq.dam.core.process.CommandLineProcess
  • com.day.cq.dam.pdfrasterizer.process.PdfRasterizerHandlingProcess
  • com.day.cq.dam.core.process.AddPropertyWorkflowProcess
  • com.day.cq.dam.core.process.CreateSubAssetsProcess
  • com.day.cq.dam.core.process.DownloadAssetProcess
  • com.day.cq.dam.word.process.ExtractImagesProcess
  • com.day.cq.dam.word.process.ExtractPlainProcess
  • com.day.cq.dam.ids.impl.process.IDSJobProcess
  • com.day.cq.dam.indd.process.INDDMediaExtractProcess
  • com.day.cq.dam.indd.process.INDDPageExtractProcess
  • com.day.cq.dam.core.impl.lightbox.LightboxUpdateAssetProcess
  • com.day.cq.dam.pim.impl.sourcing.upload.process.ProductAssetsUploadProcess
  • com.day.cq.dam.core.process.SendDownloadAssetEmailProcess
  • com.day.cq.dam.similaritysearch.internal.workflow.smarttags.StartTrainingProcess
  • com.day.cq.dam.similaritysearch.internal.workflow.smarttags.TransferTrainingDataProcess
  • com.day.cq.dam.switchengine.process.SwitchEngineHandlingProcess
  • com.day.cq.dam.core.process.GateKeeperProcess
  • com.day.cq.dam.s7dam.common.process.DMEncodeVideoWorkflowCompletedProcess
  • com.day.cq.dam.core.process.DeleteImagePreviewProcess
  • com.day.cq.dam.video.FFMpegTranscodeProcess
  • com.day.cq.dam.core.process.ThumbnailProcess
  • com.day.cq.dam.video.FFMpegThumbnailProcess
  • com.day.cq.dam.core.process.CreateWebEnabledImageProcess
  • com.day.cq.dam.core.process.CreatePdfPreviewProcess
  • com.day.cq.dam.s7dam.common.process.VideoUserUploadedThumbnailProcess
  • com.day.cq.dam.s7dam.common.process.VideoThumbnailDownloadProcess
  • com.day.cq.dam.s7dam.common.process.VideoProxyServiceProcess
  • com.day.cq.dam.scene7.impl.process.Scene7UploadProcess
  • com.day.cq.dam.s7dam.common.process.S7VideoThumbnailProcess
  • com.day.cq.dam.core.process.MetadataProcessorProcess
  • com.day.cq.dam.core.process.AssetOffloadingProcess
  • com.adobe.cq.dam.dm.process.workflow.DMImageProcess

另請參閱

recommendation-more-help
fbcff2a9-b6fe-4574-b04a-21e75df764ab