Adobe Experience Manager Assets 开发人员用例、API和参考资料 assets-cloud-service-apis
本文包含面向开发人员的建议、参考资料和资源。 Assets as a 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 as a Cloud Service,您可以使用HTTP API直接将资源上传到云存储。 上传二进制文件的步骤如下。 在外部应用程序而不是内部执行这些步骤 Experience Manager JVM。
- 提交HTTP请求. 它会通知 Experience Manage或部署了您上传新二进制文件的意图。
- PUT二进制文件的内容 初始化请求提供的一个或多个URI。
- 提交HTTP请求 通知服务器已成功上载二进制文件的内容。
该方法提供了可扩展且更高效的资产上传处理方式。 与 Experience Manager 6.5为:
- 二进制文件不通过 Experience Manager,现在只需将上传过程与为部署配置的二进制云存储进行协调即可。
- 二进制云存储可与内容交付网络(CDN)或边缘网络配合使用。 CDN为客户端选择更近的上传端点。 当数据在邻近端点之间传输较短距离时,上传性能和用户体验会得到改善,对于地理上分散的团队尤其如此。
启动上载 initiate-upload
将HTTPPOST请求提交到所需的文件夹。 在此文件夹中创建或更新资产。 包含选择器 .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,客户端应该能够处理任一URI。 即,值可以是"https://[aem_server]:[port]/content/dam.completeUpload.json"
或"/content/dam.completeUpload.json"
请参阅 完成上传.folderPath
(字符串):上传二进制文件的文件夹的完整路径。(files)
(数组):其长度和顺序与启动请求中提供的二进制信息列表的长度和顺序匹配的元素列表。fileName
(字符串):相应二进制文件的名称,在启动请求中提供。 此值应包含在完整的请求中。mimeType
(字符串):在启动请求中提供的相应二进制文件的mime类型。 此值应包含在完整的请求中。uploadToken
(字符串):相应二进制文件的上载令牌。 此值应包含在完整的请求中。uploadURIs
(数组):字符串的列表,其值是二进制文件的内容应上载到的完整URI(请参阅 上载二进制文件)。minPartSize
(数字):可以提供给任一个服务器的数据的最小长度,以字节为单位。uploadURIs
,表示存在多个URI。maxPartSize
(数字):可以提供给uploadURIs
,表示存在多个URI。
上载二进制文件 upload-binary
启动上载的输出包括一个或多个上载URI值。 如果提供了多个URI,则客户端可以按顺序将二进制文件拆分成多个部分,并向所提供的上传URI发出每个部分的PUT请求。 如果选择将二进制文件拆分为多个部分,请遵循以下准则:
- 每个部件(最后一个除外)的大小必须大于或等于
minPartSize
. - 每个部分的大小必须小于或等于
maxPartSize
. - 如果二进制文件的大小超过
maxPartSize
,将二进制文件拆分为多个部分以上传。 - 您无需使用所有URI。
如果二进制文件的大小小于或等于 maxPartSize
,您可以改为将整个二进制文件上传到单个上传URI。 如果提供了多个上传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
上传二进制文件的所有部分后,向启动数据提供的完整URI提交HTTPPOST请求。 请求正文的内容类型应为 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
状态代码。
将资产上传到AEMas a Cloud Service的示例Shell脚本 upload-assets-shell-script
以下示例shell-script说明了在AEMas 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 as a Cloud Service. API来自 Adobe Experience Manager 6.5已弃用。 以下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
另请参阅