<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                [TOC] 云函數是云引擎(LeanEngine)的一個子模塊,請確保閱讀本文檔之前,你已經閱讀了?[云引擎服務概覽](https://leancloud.cn/docs/leanengine_overview.html)。 當你開發移動端應用時,可能會有下列需求: * 應用在多平臺客戶端(Android、iOS、Windows Phone、瀏覽器等)中很多邏輯都是一樣的,希望將這部分邏輯抽取出來只維護一份。 * 有些邏輯希望能夠較靈活的調整(比如某些個性化列表的排序規則),但又不希望頻繁的更新和發布移動客戶端。 * 有些邏輯需要的數據量很大,或者運算成本高(比如某些統計匯總需求),不希望在移動客戶端進行運算,因為這樣會消耗大量的網絡流量和手機運算能力。 * 當應用執行特定操作時,由云端系統自動觸發一段邏輯(稱為?[Hook 函數](#Hook_函數)),比如:用戶注冊后對該用戶增加一些信息記錄用于統計;或某業務數據發生變化后希望做一些別的業務操作。這些代碼不適合放在移動客戶端(比如因為上面提到的幾個原因)。 * 需要定時任務,比如每天凌晨清理垃圾注冊賬號等。 這時,你可以使用云引擎的云函數。云函數是一段部署在服務端的代碼,編寫 JavaScript 或者 Python 代碼,并部署到我們的平臺上,可以很好的完成上述需求。 如果還不知道如何創建云引擎項目,本地調試并部署到云端,請閱讀?[云引擎快速入門](https://leancloud.cn/docs/leanengine_quickstart.html)。 ## [多語言支持](#多語言支持) 云引擎支持多種語言的運行環境,你可以選擇自己熟悉的語言開發應用: * [Node.js]() * [Python](https://leancloud.cn/docs/leanengine_cloudfunction_guide-python.html) * [PHP](https://leancloud.cn/docs/leanengine_cloudfunction_guide-php.html) * [Java](https://leancloud.cn/docs/leanengine_cloudfunction_guide-java.html) ## [云函數](#云函數) 示例項目中?`$PROJECT_DIR/cloud.js`?文件定義了一個很簡單的?`hello`?云函數。現在讓我們看一個明顯較復雜的例子來展示云引擎的用途。在云端進行計算的一個重要理由是,你不需要將大量的數據發送到設備上做計算,而是將這些計算放到服務端,并返回結果這一點點信息就好。 例如,你寫了一個應用,讓用戶對電影評分,一個評分對象大概是這樣: ~~~ { "movie": "夏洛特煩惱", "stars": 5, "comment": "夏洛一夢,笑成麻花" } ~~~ `stars`?表示評分,1-5。如果你想查找《夏洛特煩惱》這部電影的平均分,你可以找出這部電影的所有評分,并在設備上根據這個查詢結果計算平均分。但是這樣一來,盡管你只是需要平均分這樣一個數字,卻不得不耗費大量的帶寬來傳輸所有的評分。通過云引擎,我們可以簡單地傳入電影名稱,然后返回電影的平均分。 Cloud 函數接收 JSON 格式的請求對象,我們可以用它來傳入電影名稱。整個?[JavaScript SDK](https://leancloud.cn/docs/leanstorage_guide-js.html)?都在云引擎運行環境上有效,可以直接使用,所以我們可以使用它來查詢所有的評分。結合在一起,實現?`averageStars`?函數的代碼如下: ~~~ AV.Cloud.define('averageStars', function(request, response) { var query = new AV.Query('Review'); query.equalTo('movie', request.params.movie); query.find().then(function(results) { var sum = 0; for (var i = 0; i < results.length; i++ ) { sum += results[i].get('stars'); } response.success(sum / results.length); }).catch(function(error) { response.error('查詢失敗'); }); }); ~~~ ### [參數信息](#參數信息) Request 和 Response 會作為兩個參數傳入到云函數中: `Request`?上的屬性包括: * `params: object`:客戶端發送的參數對象,當使用?`rpc`?調用時,也可能是?`AV.Object`。 * `currentUser?: AV.User`:客戶端所關聯的用戶(根據客戶端發送的?`LC-Session`?頭)。 * `meta: object`:有關客戶端的更多信息,目前只有一個?`remoteAddress`?屬性表示客戶端的 IP。 * `sessionToken?: string`:客戶端發來的 sessionToken(`X-LC-Session`?頭)。 `Response`?上的屬性包括: * `success: function(result?)`:向客戶端發送結果,可以是包括 AV.Object 在內的各種數據類型或數組,客戶端解析方式見各 SDK 文檔。 * `error: function(err?: string)`:向客戶端返回一個錯誤,目前僅支持字符串,`Error`?等類型也會被轉換成字符串。 ### [SDK 調用云函數](#SDK_調用云函數) LeanCloud 各個語言版本的 SDK 都提供了調用云函數的接口。 ~~~ // 在 iOS SDK 中,AVCloud 提供了一系列靜態方法來實現客戶端調用云函數 // 構建傳遞給服務端的參數字典 NSDictionary *dicParameters = [NSDictionary dictionaryWithObject:@"夏洛特煩惱" forKey:@"movie"]; // 調用指定名稱的云函數 averageStars,并且傳遞參數 [AVCloud callFunctionInBackground:@"averageStars" withParameters:dicParameters block:^(id object, NSError *error) { if(error == nil){ // 處理結果 } else { // 處理報錯 } }]; ~~~ [Objective-C](#) [Java](#) [JavaScript](#) [PHP](#) [Python](#) ### [通過 REST API 調用云函數](#通過_REST_API_調用云函數) [REST API 調用云函數](https://leancloud.cn/docs/rest_api.html#云函數-1)?是 LeanCloud 云端提供的統一的訪問云函數的接口,所有的客戶端 SDK 也都是封裝了這個接口從而實現對云函數的調用。 關于調試工具,我們推薦的工具有:[Postman](http://www.getpostman.com/)?以及?[Paw](https://luckymarmot.com/paw)?,它們可以幫助開發者更方便地調試 Web API。 假設沒有以上工具,也可以使用命令行進行調試: ~~~ curl -X POST -H "Content-Type: application/json; charset=utf-8" \ -H "X-LC-Id: csXFgnEzBkodigdDUARBrEse-gzGzoHsz" \ -H "X-LC-Key: K2CE4ChmGnUwI8mMBgTRHw7y" \ -H "X-LC-Prod: 0" \ -d '{"movie":"夏洛特煩惱"}' \ https://leancloud.cn/1.1/functions/averageStars ~~~ 上述命令行實際上就是向云端發送一個 JSON 對象作為參數,參數的內容是要查詢的電影的名字。 ### [云引擎調用云函數](#云引擎調用云函數) 在云引擎中可以使用?`AV.Cloud.run`?調用?`AV.Cloud.define`?定義的云函數: ~~~ var paramsJson = { movie: '夏洛特煩惱', }; AV.Cloud.run('averageStars', paramsJson).then(function(data) { // 調用成功,得到成功的應答 data }, function(error) { // 處理調用失敗 }); ~~~ 云引擎中默認會直接進行一次本地的函數調用,而不是像客戶端一樣發起一個 HTTP 請求。如果你希望發起 HTTP 請求來調用云函數,可以傳入一個?`remote: true`?的選項(與 success 和 error 回調同級),當你在云引擎之外運行 Node SDK 時這個選項非常有用: ~~~ AV.Cloud.run('averageStars', paramsJson).then(function(data) { // 成功 }, function(error) { // 失敗 }); ~~~ ### [RPC 調用云函數](#RPC_調用云函數) RPC 調用云函數是指:云引擎會在這種調用方式下自動為 Http Response Body 做序列化,而 SDK 調用之后拿回的返回結果就是一個完整的?`AVObject`。 ~~~ NSDictionary *dicParameters = [NSDictionary dictionaryWithObject:@"夏洛特煩惱" forKey:@"movie"]; [AVCloud rpcFunctionInBackground:@"averageStars" withParameters:parameters block:^(id object, NSError *error) { if(error == nil){ // 處理結果 } else { // 處理報錯 } }]; ~~~ [Objective-C](#) [Java](#) [PHP](#) [JavaScript](#) [Python](#) ### [切換云引擎環境](#切換云引擎環境) 專業版云引擎應用有「生產環境」和「預備環境」,切換方法為: ~~~ [AVCloud setProductionMode:NO]; // 調用預備環境 ~~~ [Objective-C](#) [Java](#) [PHP](#) [JavaScript](#) [Python](#) [免費版云引擎應用只有「生產環境」](https://leancloud.cn/docs/leanengine_plan.html#免費版)?,因此以上切換方法不適用。 ### [云函數錯誤響應碼](#云函數錯誤響應碼) 錯誤響應碼允許自定義。云引擎方法最終的錯誤對象如果有?`code`?和?`message`?屬性,則響應的 body 以這兩個屬性為準,否則?`code`?為 1,?`message`?為錯誤對象的字符串形式。比如: ~~~ AV.Cloud.define('errorCode', function(req, res) { AV.User.logIn('NoThisUser', 'lalala').catch(function(err) { res.error(err); }); }); ~~~ 客戶端收到的響應:`{"code":211,"error":"Could not find user"}` ~~~ AV.Cloud.define('customErrorCode', function(request, response) { response.error({code: 123, message: 'custom error message'}); }); ~~~ 客戶端收到的響應:?`{"code":123,"error":"自定義錯誤信息"}` ### [云函數超時](#云函數超時) 云函數超時時間為 15 秒,如果超過閾值,[LeanEngine Node.js SDK](https://github.com/leancloud/leanengine-node-sdk)?將強制響應: * 客戶端收到 HTTP status code 為 503 響應,body 為?`The request timed out on the server.`。 * 服務端會出現類似這樣的日志:`LeanEngine function timeout, url=/1.1/functions/<cloudFunc>, timeout=15000`。 另外還需要注意:雖然?[LeanEngine Node.js SDK](https://github.com/leancloud/leanengine-node-sdk)?已經響應,但此時云函數可能仍在執行,但執行完畢后的響應是無意義的(不會發給客戶端,會在日志中打印一個?`Can't set headers after they are sent`?的異常)。 #### [超時的處理方案](#超時的處理方案) 我們建議將代碼中的任務轉化為異步隊列處理,以優化運行時間,避免云函數或?[定時任務](#定時任務)?發生超時。比如: * 在存儲服務中創建一個隊列表,包含?`status`?列; * 接到任務后,向隊列表保存一條記錄,`status`?值設置為「處理中」,然后直接 response,也可以把隊列對象 id 返回,如?`response.success(id);`; * 當業務處理完畢,根據處理結果更新剛才的隊列對象狀態,將?`status`?字段設置為「完成」或者「失敗」; * 在任何時候,在控制臺通過隊列 id 可以獲取某個任務的執行結果,判斷任務狀態。 ## [Hook 函數](#Hook_函數) Hook 函數本質上是云函數,但它有固定的名稱,定義之后會由系統在特定事件或操作(如數據保存前、保存后,數據更新前、更新后等等)發生時自動觸發,而不是由開發者來控制其觸發時機。 需要注意: * 通過控制臺進行?[數據導入](https://leancloud.cn/docs/dashboard_guide.html#本地數據導入_LeanCloud)?不會觸發以下任何 hook 函數。 * 使用 Hook 函數需要?[防止死循環調用](#防止死循環調用)。 * `_Installation`?表暫不支持 Hook 函數。 * Hook 函數只對當前應用的 Class 生效,[對綁定后的目標 Class 無效](https://leancloud.cn/docs/app_data_share.html#云引擎_Hook_函數)。 ### [beforeSave](#beforeSave) 在創建新對象之前,可以對數據做一些清理或驗證。例如,一條電影評論不能過長,否則界面上顯示不開,需要將其截斷至 140 個字符: ~~~ AV.Cloud.beforeSave('Review', function(request, response) { var comment = request.object.get('comment'); if (comment) { if (comment.length > 140) { // 截斷并添加... request.object.set('comment', comment.substring(0, 137) + '...'); } // 保存到數據庫中 response.success(); } else { // 不保存數據,并返回錯誤 response.error('No comment!'); } }); ~~~ ### [afterSave](#afterSave) 在創建新對象后觸發指定操作,比如當一條留言創建后再更新一下所屬帖子的評論總數: ~~~ AV.Cloud.afterSave('Comment', function(request) { var query = new AV.Query('Post'); query.get(request.object.get('post').id).then(function(post) { post.increment('comments'); post.save(); }); }); ~~~ 再如,在用戶注冊成功之后,給用戶增加一個新的屬性 from 并保存: ~~~ AV.Cloud.afterSave('_User', function(request) { console.log(request.object); request.object.set('from','LeanCloud'); request.object.save().then(function(user) { console.log('ok!'); }); }); ~~~ 如果?`afterSave`?函數調用失敗,save 請求仍然會返回成功應答給客戶端。`afterSave`?發生的任何錯誤,都將記錄到云引擎日志里,可以到?[控制臺 > 存儲 > 云引擎 > 日志](https://leancloud.cn/cloud.html?appid=csXFgnEzBkodigdDUARBrEse-gzGzoHsz#/log)?中查看。 ### [beforeUpdate](#beforeUpdate) 在更新已存在的對象前執行操作,這時你可以知道哪些字段已被修改,還可以在特定情況下拒絕本次修改: ~~~ AV.Cloud.beforeUpdate('Review', function(request, response) { // 如果 comment 字段被修改了,檢查該字段的長度 if (request.object.updatedKeys.indexOf('comment') != -1) { if (request.object.get('comment').length <= 140) { response.success(); } else { // 拒絕過長的修改 response.error('comment 長度不得超過 140 字符'); } } else { response.success(); } }); ~~~ 注意:?不要修改?`request.object`,因為對它的改動并不會保存到數據庫,但可以用?`response.error`?返回一個錯誤,拒絕這次修改。 注意:傳入的對象是一個尚未保存到數據庫的臨時對象,并不保證與最終儲存到數據庫的對象完全相同,這是因為修改中可能包含自增、數組增改、關系增改等原子操作。 ### [afterUpdate](#afterUpdate) 在更新已存在的對象后執行特定的動作,比如每次修改文章后記錄下日志: ~~~ AV.Cloud.afterUpdate('Article', function(request) { console.log('Updated article,the id is :' + request.object.id); }); ~~~ ### [beforeDelete](#beforeDelete) 在刪除一個對象之前做一些檢查工作,比如在刪除一個相冊 Album 前,先檢查一下該相冊中還有沒有照片 Photo: ~~~ AV.Cloud.beforeDelete('Album', function(request, response) { //查詢Photo中還有沒有屬于這個相冊的照片 var query = new AV.Query('Photo'); var album = AV.Object.createWithoutData('Album', request.object.id); query.equalTo('album', album); query.count().then(function(count) { if (count > 0) { //還有照片,不能刪除,調用error方法 response.error('Can\'t delete album if it still has photos.'); } else { //沒有照片,可以刪除,調用success方法 response.success(); } }, function(error) { response.error('Error ' + error.code + ' : ' + error.message + ' when getting photo count.'); }); }); ~~~ ### [afterDelete](#afterDelete) 在被刪一個對象后執行操作,例如遞減計數、刪除關聯對象等等。同樣以相冊為例,這次我們不在刪除相冊前檢查是否還有照片,而是在刪除后,同時刪除相冊中的照片: ~~~ AV.Cloud.afterDelete('Album', function(request) { var query = new AV.Query('Photo'); var album = AV.Object.createWithoutData('Album', request.object.id); query.equalTo('album', album); query.find().then(function(posts) { //查詢本相冊的照片,遍歷刪除 AV.Object.destroyAll(posts); }).then(function(error) { console.error('Error finding related comments ' + error.code + ': ' + error.message); }); }); ~~~ ### [onVerified](#onVerified) 當用戶通過郵箱或者短信驗證時,對該用戶執行特定操作。比如: ~~~ AV.Cloud.onVerified('sms', function(request, response) { console.log('onVerified: sms, user: ' + request.object); response.success(); }); ~~~ 函數的第一個參數是驗證類型。短信驗證為?`sms`,郵箱驗證為?`email`。另外,數據庫中相關的驗證字段,如?`emailVerified`?不需要修改,系統會自動更新。 ### [onLogin](#onLogin) 在用戶登錄之時執行指定操作,比如禁止在黑名單上的用戶登錄: ~~~ AV.Cloud.onLogin(function(request, response) { // 因為此時用戶還沒有登錄,所以用戶信息是保存在 request.object 對象中 console.log("on login:", request.object); if (request.object.get('username') == 'noLogin') { // 如果是 error 回調,則用戶無法登錄(收到 401 響應) response.error('Forbidden'); } else { // 如果是 success 回調,則用戶可以登錄 response.success(); } }); ~~~ ### [實時通信 Hook 函數](#實時通信_Hook_函數) 請閱讀?[實時通信概覽 · 云引擎 Hook](https://leancloud.cn/docs/realtime_v2.html#云引擎_Hook)?來了解以下函數的相關參數和用法。 #### [_messageReceived](#_messageReceived) 在消息達到服務器、群組成員已解析完成、發送給收件人之前觸發。例如,提前過濾掉聊天內容中的一些廣告類的關鍵詞: ~~~ AV.Cloud.define("_messageReceived", (request, response) => { // request.params = { // fromPeer: 'Tom', // receipt: false, // groupId: null, // system: null, // content: '{"_lctext":"耗子,起床!","_lctype":-1}', // convId: '5789a33a1b8694ad267d8040', // toPeers: ['Jerry'], // __sign: '1472200796787,a0e99be208c6bce92d516c10ff3f598de8f650b9', // bin: false, // transient: false, // sourceIP: '121.239.62.103', // timestamp: 1472200796764 // }; console.log('_messageReceived start'); let content = JSON.parse(request.params.content); let text = content._lctext; console.log('text', text); let processedContent = text.replace('XX中介', '**'); // 必須含有以下語句給服務端一個正確的返回,否則會引起異常 response.success({ content: processedContent }); console.log('_messageReceived end'); }); ~~~ #### [_receiversOffline](#_receiversOffline) 在消息發送完成時觸發、對話中某些用戶卻已經下線,此時可以根據發送的消息來生成離線消息推送的標題等等。例如截取所發送消息的前 6 個字符作為推送的標題: ~~~ AV.Cloud.define('_receiversOffline', (request, response) => { console.log('_receiversOffline start'); let params = request.params; let content = params.content; let shortContent = content; // params.content 為消息的內容 if (shortContent.length > 6) { shortContent = content.slice(0, 6); } console.log('shortContent', shortContent); let json = { // 自增未讀消息的數目,不想自增就設為數字 badge: "Increment", sound: "default", // 使用開發證書 _profile: "dev", alert: shortContent }; let pushMessage = JSON.stringify(json); response.success({ "pushMessage": pushMessage }); console.log('_receiversOffline end'); }); ~~~ #### [_messageSent](#_messageSent) 消息發送完成之后觸發,例如消息發送完后,在云引擎中打印一下日志: ~~~ AV.Cloud.define('_messageSent', (request, response) => { console.log('_messageSent start'); let params = request.params; console.log('params', params); response.success({}); console.log('_messageSent end'); // 在云引擎中打印的日志如下: // _messageSent start // params { fromPeer: 'Tom', // receipt: false, // onlinePeers: [], // content: '12345678', // convId: '5789a33a1b8694ad267d8040', // msgId: 'fptKnuYYQMGdiSt_Zs7zDA', // __sign: '1472703266575,30e1c9b325410f96c804f737035a0f6a2d86d711', // bin: false, // transient: false, // sourceIP: '114.219.127.186', // offlinePeers: [ 'Jerry' ], // timestamp: 1472703266522 } // _messageSent end }); ~~~ #### [_conversationStart](#_conversationStart) 創建對話,在簽名校驗(如果開啟)之后、實際創建之前觸發。例如對話創建時,在云引擎中打印一下日志: ~~~ AV.Cloud.define('_conversationStart', (request, response) => { console.log('_conversationStart start'); let params = request.params; console.log('params', params); response.success({}); console.log('_conversationStart end'); // 在云引擎中打印的日志如下: //_conversationStart start // params { // initBy: 'Tom', // members: ['Tom', 'Jerry'], // attr: { // name: 'Tom & Jerry' // }, // __sign: '1472703266397,b57285517a95028f8b7c34c68f419847a049ef26' // } //_conversationStart end }); ~~~ #### [_conversationStarted](#_conversationStarted) 創建對話完成觸發。例如對話創建之后,在云引擎打印一下日志: ~~~ AV.Cloud.define('_conversationStarted', (request, response) => { console.log('_conversationStarted start'); let params = request.params; console.log('params', params); response.success({}); console.log('_conversationStarted end'); // 在云引擎中打印的日志如下: // _conversationStarted start // params { // convId: '5789a33a1b8694ad267d8040', // __sign: '1472723167361,f5ceedde159408002fc4edb96b72aafa14bc60bb' // } // _conversationStarted end }); ~~~ #### [_conversationAdd](#_conversationAdd) 向對話添加成員,在簽名校驗(如果開啟)之后、實際加入之前,包括主動加入和被其他用戶加入兩種情況都會觸發,注意在創建對話時傳入了其他用戶的 Client Id 作為 Member 參數,不會觸發 _conversationAdd?。例如在云引擎中打印成員加入時的日志: ~~~ AV.Cloud.define('_conversationAdd', (request, response) => { console.log('_conversationAdd start'); let params = request.params; console.log('params', params); response.success({}); console.log('_conversationAdd end'); // 在云引擎中打印的日志如下: // _conversationAdd start // params { // initBy: 'Tom', // members: ['Mary'], // convId: '5789a33a1b8694ad267d8040', // __sign: '1472786231813,a262494c252e82cb7a342a3c62c6d15fffbed5a0' // } // _conversationAdd end }); ~~~ #### [_conversationRemove](#_conversationRemove) 從對話中踢出成員,在簽名校驗(如果開啟)之后、實際踢出之前觸發,用戶自己退出對話不會觸發。例如在踢出某一個成員時,在云引擎日志中打印出該成員的 Client Id: ~~~ AV.Cloud.define('_conversationRemove', (request, response) => { console.log('_conversationRemove start'); let params = request.params; console.log('params', params); response.success({}); console.log('removed client Id:', params.members[0]); console.log('_conversationRemove end'); // 在云引擎中打印的日志如下: // _conversationRemove start // params { // initBy: 'Tom', // members: ['Jerry'], // convId: '57c8f3ac92509726c3dadaba', // __sign: '1472787372605,abdf92b1c2fc4c9820bc02304f192dab6473cd38' // } //removed client Id: Jerry // _conversationRemove end }); ~~~ #### [_conversationUpdate](#_conversationUpdate) 修改對話屬性、設置或取消對話消息提醒,在實際修改之前觸發。例如在更新發生時,在云引擎日志中打印出對話的名稱: ~~~ AV.Cloud.define('_conversationUpdate', (request, response) => { console.log('_conversationUpdate start'); let params = request.params; console.log('params', params); console.log('name', params.attr.name); response.success({}); console.log('_conversationUpdate end'); // 在云引擎中打印的日志如下: // _conversationUpdate start // params { // convId: '57c9208292509726c3dadb4b', // initBy: 'Tom', // attr: { // name: '聰明的喵星人', // type: 'public' // }, // name 聰明的喵星人 // _conversationUpdate end }); ~~~ ### [防止死循環調用](#防止死循環調用) 在實際使用中有這樣一種場景:在?`Post`?類的?`afterUpdate`?Hook 函數中,對傳入的?`Post`?對象做了修改并且保存,而這個保存動作又會再次觸發?`afterUpdate`,由此形成死循環。針對這種情況,我們為所有 Hook 函數傳入的?`request.object`?對象做了處理,以阻止死循環調用的產生。 不過請注意,以下情況還需要開發者自行處理: * 對傳入的?`request.object`?對象進行?`fetch`?操作。 * 重新構造傳入的?`request.object`?對象,如使用?`AV.Object.createWithoutData()`?方法。 對于使用上述方式產生的對象,請根據需要自行調用以下 API: * `object.disableBeforeHook()`?或 * `object.disableAfterHook()` 這樣,對象的保存或刪除動作就不會再次觸發相關的 Hook 函數。 ~~~ AV.Cloud.afterUpdate('Post', function(request) { // 直接修改并保存對象不會再次觸發 afterUpdate Hook 函數 request.object.set('foo', 'bar'); request.object.save().then(function(obj) { // 你的業務邏輯 }).catch(console.error); // 如果有 fetch 操作,則需要在新獲得的對象上調用相關的 disable 方法 // 來確保不會再次觸發 Hook 函數 request.object.fetch().then(function(obj) { obj.disableAfterHook(); obj.set('foo', 'bar'); return obj.save(); }).then(function(obj) { // 你的業務邏輯 }).catch(console.error); // 如果是其他方式構建對象,則需要在新構建的對象上調用相關的 disable 方法 // 來確保不會再次觸發 Hook 函數 var obj = AV.Object.createWithoutData('Post', request.object.id); obj.disableAfterHook(); obj.set('foo', 'bar'); obj.save().then(function(obj) { // 你的業務邏輯 }).catch(console.error); }); ~~~ 提示:云引擎 Node.js 環境從?[0.3.0](https://github.com/leancloud/leanengine-node-sdk/blob/master/CHANGELOG.md#v030-20151231)?開始支持?`object.disableBeforeHook()`?和?`object.disableAfterHook()`。 ### [Hook 函數錯誤響應碼](#Hook_函數錯誤響應碼) 為?`beforeSave`?這類的 hook 函數定義錯誤碼,需要這樣: ~~~ AV.Cloud.beforeSave('Review', function(request, response) { // 使用 JSON.stringify() 將 object 變為字符串 response.error(JSON.stringify({ code: 123, message: '自定義錯誤信息' })); }); ~~~ 客戶端收到的響應為:`Cloud Code validation failed. Error detail : {"code":123, "message": "自定義錯誤信息"}`,然后通過截取字符串的方式取出錯誤信息,再轉換成需要的對象。 ### [Hook 函數超時](#Hook_函數超時) Hook 函數的超時時間為 3 秒。如果 Hook 函數被其他的云函數調用(比如因為 save 對象而觸發?`beforeSave`?和?`afterSave`),那么它們的超時時間會進一步被其他云函數調用的剩余時間限制。 例如,如果一個?`beforeSave`?函數是被一個已經運行了 13 秒的云函數觸發,那么?`beforeSave`?函數就只剩下 2 秒的時間來運行。同時請參考?[云函數超時](#云函數超時)。 ## [在線編寫云函數](#在線編寫云函數) 很多人使用 LeanEngine 是為了在服務端提供一些個性化的方法供各終端調用,而不希望關心諸如代碼托管、npm 依賴管理等問題。為此我們提供了在線維護云函數的功能。 使用此功能需要注意: * 在定義的函數會覆蓋你之前用 Git 或命令行部署的項目。 * 目前只能在線編寫云函數和 Hook,不支持托管靜態網頁、編寫動態路由。 在?[控制臺 > 存儲 > 云引擎 > 部署 > 在線編輯](https://leancloud.cn/cloud.html?appid=csXFgnEzBkodigdDUARBrEse-gzGzoHsz#/deploy/online)?標簽頁,可以: * 創建函數:指定函數類型,函數名稱,函數體的具體代碼,注釋等信息,然后「保存」即可創建一個云函數。 * 部署:選擇要部署的環境,點擊「部署」即可看到部署過程和結果。 * 預覽:會將所有函數匯總并生成一個完整的代碼段,可以確認代碼,或者將其保存為?`cloud.js`?覆蓋項目模板的同名文件,即可快速的轉換為使用項目部署。 * 維護云函數:可以編輯已有云函數,查看保存歷史,以及刪除云函數。 提示:云函數編輯之后需要重新部署才能生效。 ## [定時任務](#定時任務) 定時任務可以按照設定,以一定間隔自動完成指定動作,比如半夜清理過期數據,每周一向所有用戶發送推送消息等等。定時任務的最小時間單位是秒,正常情況下時間誤差都可以控制在秒級別。 定時任務是普通的云函數,也會遇到?[超時問題](#云函數超時),具體請參考?[超時處理方案](#超時的處理方案)。 部署云引擎之后,進入?[控制臺 > 存儲 > 云引擎 > 定時任務](https://leancloud.cn/cloud.html?appid=csXFgnEzBkodigdDUARBrEse-gzGzoHsz#/task),點擊?創建定時器,然后設定執行的函數名稱、執行環境等等。例如定義一個打印循環打印日志的任務?`log_timer`: ~~~ AV.Cloud.define('log_timer', function(request, response){ console.log('Log in timer.'); return response.success(); }); ~~~ 定時器創建后,其狀態為未運行,需要點擊?啟用?來激活。之后其執行日志可以通過?[日志](https://leancloud.cn/cloud.html?appid=csXFgnEzBkodigdDUARBrEse-gzGzoHsz#/log)?查看。 定時任務分為兩類: * 使用 Cron 表達式安排調度 * 以秒為單位的簡單循環調度 以 Cron 表達式為例,比如每周一早上 8 點準時發送推送消息給用戶: ~~~ AV.Cloud.define('push_timer', function(request, response){ AV.Push.send({ channels: ['Public'], data: { alert: 'Public message' } }); return response.success(); }); ~~~ 創建定時器的時候,選擇?Cron 表達式?并填入?`0 0 8 ? * MON`。 ### [Cron 表達式](#Cron_表達式) Cron 表達式的基本語法為: ~~~ <秒> <分鐘> <小時> <日期 day-of-month> <月份> <星期 day-of-week> <年> ~~~ | 位置 | 字段 | 約束 | 取值 | 可使用的特殊字符 | | --- | --- | --- | --- | --- | | 1 | 秒 | 必須 | 0-59 | `, - * /` | | 2 | 分鐘 | 必須 | 0-59 | `, - * /` | | 3 | 小時 | 必須 | 0-23(0 為午夜) | `, - * /` | | 4 | 日期 | 必須 | 1-31 | `, - * ? / L W` | | 5 | 月份 | 必須 | 1-12、JAN-DEC | `, - * /` | | 6 | 星期 | 必須 | 1-7、SUN-SAT | `, - * ? / L #` | | 7 | 年 | 可選 | 空、1970-2099 | `, - * /` | 特殊字符的用法: | 字符 | 含義 | 用法 | | --- | --- | --- | | `*` | 所有值 | 代表一個字段的所有可能取值。如將?`<分鐘>`?設為?*,表示每一分鐘。 | | `?` | 不指定值 | 用于可以使用該字符的兩個字段中的一個,在一個表達式中只能出現一次。如任務執行時間為每月 10 號,星期幾無所謂,那么表達式中?`<日期>`?設為?10,`<星期>`?設為??。 | | `-` | 范圍 | 如?`<小時>`?為?10-12,即10 點、11 點、12 點。 | | `,` | 分隔多個值 | 如?`<星期>`?為?MON,WED,FRI,即周一、周三、周五。 | | `/` | 增量 | 如?`<秒>`?設為?0/15,即從 0 秒開始,以 15 秒為增量,包括 0、15、30、45 秒;5/15?即 5、20、35、50 秒。*/?與?0/?等效,如?`<日期>`?設為?1/3,即從每個月的第一天開始,每 3 天(即每隔 2 天)執行一次任務。 | | `L` | 最后 | 其含義隨字段的不同而不同。?`<日期>`?中使用?L?代表每月最后一天,如 1 月 31 號、2 月 28 日(非閏年);`<星期>`?中單獨使用?L,則與使用?7?或?SAT?等效,若前面搭配其他值使用,如?6L,則表示每月的最后一個星期五。 注意,在 L 之前不要使用多個值或范圍,如?1,2L、1-2L,否則會產生錯誤結果。 | | `W` | weekday | 周一到周五的任意一天,離指定日期最近的非周末的那一天。 `<日期>`?為?15W?即離 15 號最近的非周末的一天;如果 15 號是周六,任務則會在 14 號周五觸發,如果 15 號是周日,則在 16 號周一觸發,如果 15 號是周二,則周二當天觸發。 `<日期>`?為?1W,如果 1 號是周六,任務則會在 3 號周一觸發,因為不能向前跨月來計算天數。 在?`<日期>`?中?W?之前只能使用一個數值,不能使用多個值或范圍。LW?可在?`<日期>`?中組合使用,表示每月最后一個非周末的一天。 | | `#` | 第 N 次 | 如?`<星期>`?為?6#3?代表每月第三個周五,2#1?為每月頭一個周一,4#5?為每月第五個周三;如果當月沒有第五周,則?#5?不會產生作用。 | 各字段以空格或空白隔開。JAN-DEC、SUN-SAT 這些值不區分大小寫,比如 MON 和 mon 效果一樣。更詳細的使用方法請參考?[Quartz 文檔(英文)](http://www.quartz-scheduler.org/documentation/quartz-1.x/tutorials/crontrigger)?。 舉例如下: | 表達式 | 說明 | | --- | --- | | `0 0/5 * * * ?` | 每隔 5 分鐘執行一次 | | `10 0/5 * * * ?` | 每隔 5 分鐘執行一次,每次執行都在分鐘開始的 10 秒,例如 10:00:10、10:05:10 等等。 | | `0 30 10-13 ? * WED,FRI` | 每周三和每周五的 10:30、11:30、12:30、13:30 執行。 | | `0 0/30 8-9 5,20 * ?` | 每個月的 5 號和 20 號的 8 點和 10 點之間每隔 30 分鐘執行一次,也就是 8:00、8:30、9:00 和 9:30。 | ### [定時器數量](#定時器數量) 生產環境和預備環境的定時器數量都限制在 5 個以內,也就是說你總共最多可以創建 10 個定時器。 ### [錯誤信息](#錯誤信息) 定時器執行后的日志會記錄在?[控制臺 > 存儲 > 云引擎 > 其它 > 日志](https://leancloud.cn/cloud.html?appid=csXFgnEzBkodigdDUARBrEse-gzGzoHsz#/log)?中,以下為常見的錯誤信息及原因。 * timerAction timed-out and no fallback available. 某個定時器觸發的云函數,因 15 秒內沒有響應而超時(可參考?[對云函數調用超時的處理](#超時的處理方案))。 * timerAction short-circuited and no fallback available. 某個定時器觸發的云函數,因為太多次超時而停止觸發。 ## [權限說明](#權限說明) 云引擎可以有超級權限,使用 Master key 調用所有 API,因此會忽略 ACL 和 Class Permission 限制。你只需要使用下列代碼來初始化 SDK(在線定義默認就有超級權限): ~~~ //參數依次為 AppId, AppKey, MasterKey AV.init({ appId: 'csXFgnEzBkodigdDUARBrEse-gzGzoHsz', appKey: 'K2CE4ChmGnUwI8mMBgTRHw7y', masterkey: 'l3fwovKapDmHHC6lDHNfJhR5' }) AV.Cloud.useMasterKey(); ~~~ 如果在你的服務端環境里也想做到超級權限,也可以使用該方法初始化。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看