本文中含有需要您注意的重要提示信息,忽略該信息可能對您的業務造成影響,請務必仔細閱讀。
如果您需要為OSS觸發器設置多個文件前綴和文件后綴,或者希望在一個OSS Bucket中關聯10個以上的觸發器,您可以創建EventBridge類別的OSS觸發器,以便輕松應對文件上傳等事件。
注意事項
EventBridge類別的OSS觸發器與原生OSS觸發器不同,您需要關注以下注意事項。
原生OSS觸發器,一個Bucket最多支持關聯10個觸發器。如您需要在一個Bucket內,關聯更多的OSS觸發器,可以選擇創建EventBridge類別的OSS觸發器。
說明通常情況下,不推薦為一個Bucket關聯10個以上的觸發器。如需創建,建議您創建新的Bucket,并基于新的Bucket創建觸發器。
與事件總線EventBridge的資源限制數一致,目前最多支持創建50個EventBridge類別的OSS觸發器。更多信息,請參見使用限制。
EventBridge類別的OSS觸發器無需保證語義唯一性,即事件類型、文件前綴和文件后綴組成的語義無需唯一。
EventBridge類別的OSS觸發器支持同時配置多個文件前綴和文件后綴,但是文件前綴和文件后綴不支持模糊匹配和正則匹配。
EventBridge類別的OSS觸發器創建成功后,不會立即生效。需等待約30s后,對象存儲OSS相關操作事件才能觸發函數。
示例場景
您可以配置一個OSS觸發器,在觸發規則中設置前綴為source和test,后綴為.rar和.zip。當有壓縮文件存入指定的OSS Bucket中的source或者test目錄下,且文件后綴為.rar或者.zip時,會自動觸發函數執行。函數執行完成后,將解壓縮后的文件存放到同一個Bucket的其他目錄下。
前提條件
事件總線EventBridge
函數計算
對象存儲OSS
步驟一:創建EventBridge類別的OSS觸發器
登錄函數計算控制臺,在左側導航欄,單擊函數。
在頂部菜單欄,選擇地域,然后在函數頁面,單擊目標函數。
在函數配置頁面,選擇配置頁簽,在左側導航欄,單擊觸發器,然后單擊創建觸發器。
在創建觸發器面板,觸發器類型選擇云產品事件觸發器類型中的對象存儲OSS,設置其余配置項,然后單擊確定。
配置項
操作
本文示例
名稱
填寫自定義的觸發器名稱。
oss-trigger
版本或別名
默認值為LATEST。如果您需要創建其他版本或別名的觸發器,需先在函數詳情頁的版本或別名下拉列表選擇該版本。關于版本和別名的簡介,請參見管理版本和管理別名。
LATEST
Bucket 名稱
選擇已創建的OSS Bucket。
bucket-zh****
文件前綴
輸入要匹配的文件名稱的前綴。函數計算建議您配置前綴和后綴,避免觸發事件嵌套循環觸發引起額外費用。
您可以在控制臺單擊+添加文件前綴同時添加多個文件前綴。
重要文件前綴不能以
/
開頭,否則會導致OSS觸發器無法被觸發。source
test
文件后綴
輸入要匹配的文件名稱的后綴。函數計算建議您配置前綴和后綴,避免觸發事件嵌套循環觸發引起額外費用。
您可以在控制臺單擊+添加文件后綴同時添加多個文件后綴。
png
事件類型
選擇一個或多個觸發事件。關于函數計算的事件類型,請參見OSS事件定義。
oss:ObjectCreated:PutObject
,oss:ObjectCreated:PostObject
,oss:ObjectCreated:CompleteMultipartUpload
事件模式內容
您創建文件前綴、文件后綴和觸發事件后,該配置項自動填充。
重要請謹慎修改事件模式內容,否則可能導致觸發器觸發失敗。請了解事件模式的詳細規則后,再決定是否修改。更多信息,請參見事件模式。
{ "source":[ "acs.oss" ] }
調用方式
選擇函數調用方式,默認為同步調用。
同步調用
觸發器啟用狀態
創建觸發器后是否立即啟用。默認勾選啟用觸發器,即創建觸發器后立即啟用觸發器。
不涉及
推送格式
指定函數入口參數的數據格式,該數據通過函數的Event參數進行傳遞。
CloudEvents:以通用格式描述事件數據的規范,包含事件描述以及事件負載數據,旨在簡化不同服務、平臺間的事件聲明和傳輸。
RawData:只投遞事件負載數據,不包含CloudEvents格式中的其它元數據信息。
說明兩種類型的OSS觸發器的推送格式不同。原生OSS觸發器與EventBridge類別的OSS觸發器不同,其Event參數支持OSSEvents模板,即阿里云對象存儲OSS生成的事件格式。
CloudEvents
創建完成后,在觸發器名稱列表中顯示已創建的觸發器。如需對創建的觸發器進行修改或刪除,具體操作,請參見觸發器管理。
步驟二:配置函數入口參數
EventBridge類別的OSS觸發器事件源會以CloudEvents模板作為輸入參數傳遞給函數,您可以手動將Event傳給函數模擬觸發事件。
在函數配置頁面的代碼頁簽,單擊測試函數右側的圖標,從下拉列表中,選擇配置測試參數。
在配置測試參數面板,選擇創建新測試事件或編輯已有測試事件,填寫事件名稱和事件內容,然后單擊確定。
Event是函數計算的入口參數,當指定的OSS Bucket發生指定事件時,會將事件數據以JSON格式發送給綁定的函數。具體格式如下所示。
{ "datacontenttype": "application/json;charset=utf-8", "aliyunaccountid": "143199913****", "data": { "eventVersion": "1.0", "responseElements": { "requestId": "6364D216511B143733C5A67B" }, "eventSource": "acs:oss", "eventTime": "2023-11-04T08:49:26.000Z", "requestParameters": { "sourceIPAddress": "140.205.XX.XX" }, "eventName": "ObjectCreated:PutObject", "userIdentity": { "principalId": "143199913****" }, "region": "cn-hangzhou", "oss": { "bucket": { "name": "bucket-zh***", "arn": "acs:oss:cn-hangzhou:143199913****:bucket-zh***", "virtualBucket": "", "ownerIdentity": "143199913****" }, "ossSchemaVersion": "1.0", "object": { "size": 13, "objectMeta": { "mimeType": "text/plain" }, "deltaSize": 13, "eTag": "59CA0EFA9F5633CB0371BBC0355478D8", "key": "source/a.png" } } }, "subject": "acs:oss:cn-hangzhou:143199913****:bucket-zh***/source/a.png", "aliyunoriginalaccountid": "143199913****", "source": "acs.oss", "type": "oss:ObjectCreated:PutObject", "aliyunpublishtime": "203-11-04T08:49:26.745Z", "specversion": "1.0", "aliyuneventbusname": "default", "id": "6364D216511B143733C5A67B", "time": "2023-11-04T08:49:26Z", "aliyunregionid": "cn-hangzhou" }
Event參數中不同屬性字段的解釋如下表所示。
參數
類型
示例值
描述
datacontenttype
String
application/json;charset=utf-8
參數data的內容形式。datacontenttype只支持application/json;charset=utf-8格式。
aliyunaccountid
String
143199913****
阿里云賬號ID。您的阿里云賬號ID,可在函數計算控制臺的概覽頁面的常用信息區域獲取。
data
{}
OSS事件內容,為JSON對象。CloudEvents包含事件發生時由OSS定義的上下文,data中封裝了這些信息。
subject
String
acs:oss:cn-hangzhou:143199913****:bucket-zh****/source/a.png
事件主題。
格式為
acs:oss:<region>:<your_account_id>:<your_bucket>
,需修改<region>
為您創建函數時選擇的地域,修改<your_account_id>
為您的阿里云賬號ID,修改<your_bucket>
為相同地域下您實際已經創建的Bucket名稱。aliyunoriginalaccountid
String
143199913****
阿里云賬號ID。
source
String
acs.oss
事件源。OSS觸發器固定為
acs.oss
。type
String
oss:ObjectCreated:PutObject
事件類型。
aliyunpublishtime
Timestamp
2023-11-04T08:49:26.745Z
接收事件的時間。
specversion
String
1.0
CloudEvents協議版本。
aliyuneventbusname
String
default
接收事件的事件總線名稱。
id
String
6364D216511B143733C5A67B
事件ID。
time
Timestamp
2023-11-04T08:49:26Z
事件產生的時間。
aliyunregionid
String
cn-hangzhou
接收事件的地域。
aliyunpublishaddr
String
140.205.XX.XX
接收事件的服務器地址。
Event參數中data的以下內容需根據實際情況修改。
userIdentity.principalId
:修改為您的阿里云賬號ID。region
:修改為您創建函數時選擇的地域。oss.bucket.name
:修改為函數相同地域下您實際已經創建的Bucket名稱。oss.bucket.arn
:格式為acs:oss:<region>:<your_account_id>:<your_bucket>
,需修改<region>
為您創建函數時選擇的地域,修改<your_account_id>
為您的阿里云賬號ID,修改<your_bucket>
為相同地域下您實際已經創建的Bucket名稱。oss.bucket.ownerIdentity
:修改為您的阿里云賬號ID。object.key
:修改為您實際已經上傳到目標Bucket下的文件。說明請確保您配置的Bucket中存在指定的文件,本文示例為source/a.png,否則無法觸發函數執行,或者函數執行會失敗。
步驟三:編寫函數代碼并測試
OSS觸發器創建完成后,您可以開始編寫函數代碼并測試,以驗證代碼的正確性。在實際操作過程中發生OSS事件時,會自動觸發函數執行。
代碼中一定要避免循環觸發,否則會產生不必要的費用。一個典型的循環觸發場景是OSS的某個Bucket上傳文件事件觸發函數執行,此函數執行完成后又生成了一個或多個文件再寫回到OSS的Bucket里,這個寫入動作又觸發了函數執行,形成了鏈狀循環。更多信息,請參見OSS觸發器觸發規則。
在函數配置頁面的代碼頁簽,在代碼編輯器中編寫代碼,然后單擊部署代碼。
執行代碼前的準備工作和代碼示例如下。
說明如果您要在您的函數中讀寫OSS資源,建議使用OSS內網服務地址進行訪問,避免使用公網訪問,產生公網費用。關于OSS內網服務地址的格式,請參見訪問域名和數據中心。
/*準備工作: 1.請先在終端中執行以下代碼安裝package.json文件和jimp圖片處理模塊。 a.在終端執行npm init安裝package.json文件。 b.在終端執行npm install jimp安裝jimp圖片處理模塊。 2.請確保函數的函數入口(handler)為index.handler。 */ 'use strict'; console.log('Loading function ...'); var oss = require('ali-oss'); var fs = require('fs'); var jimp = require("jimp"); module.exports.handler = function (eventBuf, ctx, callback) { console.log('Received event:', eventBuf.toString()); var event = JSON.parse(eventBuf); var ossEvent = event.data; // OSS地域以“oss-”為前綴,例如“oss-cn-shanghai”。 var ossRegion = "oss-" + ossEvent.region; // 創建OSS客戶端。 var client = new oss({ region: ossRegion, /* 阿里云賬號AccessKey擁有所有API的訪問權限,建議您使用RAM用戶進行API訪問或日常運維。 建議不要把AccessKey ID和AccessKey Secret保存到工程代碼里,否則可能導致AccessKey泄露,威脅您賬號下所有資源的安全。 本示例以從上下文中獲取AccessKeyId/AccessSecret為例。 */ accessKeyId: ctx.credentials.accessKeyId, accessKeySecret: ctx.credentials.accessKeySecret, stsToken: ctx.credentials.securityToken }); // 從事件中獲取Bucket名稱。 client.useBucket(ossEvent.oss.bucket.name); // 處理后的圖片被存儲至processed/目錄。 var newKey = ossEvent.oss.object.key.replace("source/", "processed/"); var tmpFile = "/tmp/processed.png"; // 獲取OSS文件對象。 console.log('Getting object: ', ossEvent.oss.object.key) client.get(ossEvent.oss.object.key).then(function (val) { // 從緩存中讀取OSS文件對象內容。 jimp.read(val.content, function (err, image) { if (err) { console.error("Failed to read image"); callback(err); return; } // 調整圖片大小,并將其保存至tmp文件中。 image.resize(128, 128).write(tmpFile, function (err) { if (err) { console.error("Failed to write image locally"); callback(err); return; } // 將讀取到的文件對象上傳到OSS存儲空間中并重新命名。 console.log('Putting object: ', newKey); client.put(newKey, tmpFile).then(function (val) { console.log('Put object:', val); callback(null, val); return; }).catch(function (err) { console.error('Failed to put object: %j', err); callback(err); return }); }); }); }).catch(function (err) { console.error('Failed to get object: %j', err); callback(err); return }); };
#準備工作: #1.請確保函數配置的角色具有訪問對象存儲OSS的權限。您可以登錄RAM控制臺,為該角色添加訪問對象存儲OSS的權限。 #2.請確保函數的請求處理程序(handler)為index.handler。 # -*- coding: utf-8 -*- import oss2, json from wand.image import Image def handler(event, context): evt = json.loads(event) creds = context.credentials # Required by OSS sdk # 阿里云賬號AccessKey擁有所有API的訪問權限,建議您使用RAM用戶進行API訪問或日常運維。 # 建議不要把AccessKey ID和AccessKey Secret保存到工程代碼里,否則可能導致AccessKey泄露,威脅您賬號下所有資源的安全。 # 本示例以從上下文中獲取AccessKeyId/AccessSecret為例。 auth=oss2.StsAuth( creds.access_key_id, creds.access_key_secret, creds.security_token) evt = evt['data'] bucket_name = evt['oss']['bucket']['name'] endpoint = 'oss-' + evt['region'] + '-internal.aliyuncs.com' bucket = oss2.Bucket(auth, endpoint, bucket_name) objectName = evt['oss']['object']['key'] # Processed images will be saved to processed/ newKey = objectName.replace("source/", "processed/") remote_stream = bucket.get_object(objectName) if not remote_stream: return remote_stream = remote_stream.read() with Image(blob=remote_stream) as img: with img.clone() as i: i.resize(128, 128) new_blob = i.make_blob() bucket.put_object(newKey, new_blob)
/*準備工作: 1.請確保函數配置的角色具有訪問對象存儲OSS的權限。您可以登錄RAM控制臺,為該角色添加訪問對象存儲OSS的權限。 2.請確保函數的請求處理程序(handler)為index.handler。 */ <?php use OSS\OssClient; function handler($event, $context) { $event = json_decode($event, $assoc = true); /* 阿里云賬號AccessKey擁有所有API的訪問權限,建議您使用RAM用戶進行API訪問或日常運維。 建議不要把AccessKey ID和AccessKey Secret保存到工程代碼里,否則可能導致AccessKey泄露,威脅您賬號下所有資源的安全。 本示例以從上下文中獲取AccessKey/AccessSecretKey為例。 */ $accessKeyId = $context["credentials"]["accessKeyId"]; $accessKeySecret = $context["credentials"]["accessKeySecret"]; $securityToken = $context["credentials"]["securityToken"]; $evt = $event['data']; $bucketName = $evt['oss']['bucket']['name']; $endpoint = 'oss-' . $evt['region'] . '-internal.aliyuncs.com'; $objectName = $evt['oss']['object']['key']; $newKey = str_replace("source/", "processed/", $objectName); try { $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint, false, $securityToken); $content = $ossClient->getObject($bucketName , $objectName); if ($content == null || $content == "") { return; } $imagick = new Imagick(); $imagick->readImageBlob($content); $imagick->resizeImage(128, 128, Imagick::FILTER_LANCZOS, 1); $ossClient->putObject($bucketName, $newKey, $imagick->getImageBlob()); } catch (OssException $e) { print($e->getMessage()); } }
/*準備工作: 1.請先增加如下依賴到pom.xml。 <dependencies> <dependency> <groupId>com.aliyun.fc.runtime</groupId> <artifactId>fc-java-core</artifactId> <version>1.4.1</version> </dependency> <dependency> <groupId>com.aliyun.fc.runtime</groupId> <artifactId>fc-java-event</artifactId> <version>1.2.0</version> </dependency> </dependencies> 2.請確保函數的函數入口(handler)為example.App::handleRequest。 */ package example; import java.io.*; import java.util.Map; import com.aliyun.fc.runtime.Context; import com.aliyun.fc.runtime.StreamRequestHandler; import com.aliyun.fc.runtime.event.OSSEvent.Event; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; public class App implements StreamRequestHandler { private static final ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); public static final class CloudEvent { public final String id; public final String source; public final String specversion; public final String type; public final String datacontenttype; public final String dataschema; public final String subject; public final String time; public final Map<String, ?> extensions; public final Event data; @JsonCreator public CloudEvent(@JsonProperty("id") String id, @JsonProperty("source") String source, @JsonProperty("specversion") String specversion, @JsonProperty("type") String type, @JsonProperty("datacontenttype") String datacontenttype, @JsonProperty("dataschema") String dataschema, @JsonProperty("subject") String subject, @JsonProperty("time") String time, @JsonProperty("extensions") Map<String, ?> extensions, @JsonProperty("data") Event data) { this.id = id; this.source = source; this.specversion = specversion; this.type = type; this.datacontenttype = datacontenttype; this.dataschema = dataschema; this.subject = subject; this.time = time; this.extensions = extensions; this.data = data; } public String getId() { return this.id; } public String getSource() { return this.source; } public String getSpecversion() { return this.specversion; } public String getType() { return this.type; } public String getDatacontenttype() { return this.datacontenttype; } public String getDataschema() { return this.dataschema; } public String getSubject() { return this.subject; } public String getTime() { return this.time; } public Map<String, ?> getExtensions() { return this.extensions; } public Event getData() { return this.data; } } @Override public void handleRequest( InputStream inputStream, OutputStream outputStream, Context context) throws IOException { CloudEvent cloudEvents = mapper.readValue(inputStream, new TypeReference<CloudEvent>() {}); Event ossEvent = cloudEvents.getData(); context.getLogger().info(String.format("received %s from %s @ %s", ossEvent.eventName, ossEvent.eventSource, ossEvent.region)); outputStream.write(String.format("received %s from %s @ %s", ossEvent.eventName, ossEvent.eventSource, ossEvent.region).getBytes()); outputStream.write(String.format("received bucket %s", ossEvent.oss.bucket.arn).getBytes()); outputStream.write(String.format("received object %s and it's size is %s", ossEvent.oss.object.key, ossEvent.oss.object.size).getBytes()); } }
單擊測試函數。
執行完成后,您可以在代碼頁簽的上方查看執行結果。
常見問題
相關文檔
如果您想了解可以配置的OSS事件類型,請參見OSS事件定義。
如果您需要對創建的觸發器進行修改或刪除,具體操作請參見更新觸發器配置。
觸發器相關問題
如果您希望查看函數的執行觸發了哪個事件,可以手動在代碼邏輯中打印事件類型日志,具體請參見日志記錄。
如果您希望在函數中調用另一個函數,可以使用API調用指定函數或使用函數工作流編排函數。如果調用的函數需要執行耗時操作且均為異步調用,可以配置異步調用目標服務。具體請參見函數可以相互調用嗎?和配置異步調用目標服務。