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支援所有或部分作業。
資產上傳 asset-upload
在Experience Manager中以Cloud Service身分,您可以使用HTTP API直接將資產上傳到雲端儲存空間。 上傳二進位檔案的步驟如下。 在外部應用程式中執行這些步驟,而不是在Experience Manager JVM中執行。
方法提供可擴充且效能更高的資產上傳處理方式。 與Experience Manager 6.5的差異如下:
- 二進位檔不會通過Experience Manager,現在只是協調上傳程式與為部署設定的二進位雲端儲存空間。
- 二進位雲端儲存空間可與內容傳遞網路(CDN)或Edge網路搭配使用。 CDN會選取較接近使用者端的上傳端點。 當資料傳輸至附近端點的距離較短時,上傳效能和使用者體驗會改善,尤其是對於分散各地的團隊。
啟動上傳 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合約無法保證此方法可正常運作,而且可能會造成零件大小超出minPartSize
到maxPartSize
的範圍。 這可能會造成二進位上傳失敗。
同樣地,最簡單且最安全的方式是隻使用大小等於maxPartSize
的部分。
如果上傳成功,伺服器會以201
狀態代碼回應每個要求。
完成上傳 complete-upload
上傳二進位檔案的所有部分後,將HTTPPOST請求提交至初始化資料提供的完整URI。 要求內文的內容型別應為application/x-www-form-urlencoded
表單資料,包含下列欄位。
fileName
mimeType
uploadToken
createVersion
True
和指定名稱的資產存在,則Experience Manager會建立該資產的新版本。versionLabel
versionComment
replace
True
和指定名稱的資產存在,Experience Manager會刪除該資產,然後重新建立它。uploadDuration
fileSize
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提供開放原始碼程式庫和工具:
已棄用的資產上傳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
另請參閱