對(duì)于復(fù)雜的應(yīng)用程序,有時(shí)您需要一些不在移動(dòng)設(shè)備上運(yùn)行的邏輯。 ?Cloud Code
? 使這成為可能。
?Cloud Code
? 易于使用,因?yàn)樗⒃谥С謹(jǐn)?shù)千個(gè)應(yīng)用程序的同一個(gè) ?Moralis JavaScript SDK
? 之上。 唯一的區(qū)別是此代碼在您的 ?Moralis Dapp
? 中運(yùn)行,而不是在用戶的移動(dòng)設(shè)備上運(yùn)行。 當(dāng)您更新您的云代碼時(shí),它會(huì)立即可供所有移動(dòng)環(huán)境使用。 您不必等待應(yīng)用程序的新版本。 這使您可以即時(shí)更改應(yīng)用程序行為并更快地添加新功能。
即使您只熟悉移動(dòng)開(kāi)發(fā),我們也希望您會(huì)發(fā)現(xiàn) ?Cloud Code
? 簡(jiǎn)單易用。
您可以直接在儀表板上編輯云代碼或設(shè)置 IDE。
讓我們看一個(gè)稍微復(fù)雜一點(diǎn)的例子,其中 ?Cloud Code
? 很有用。 在云中進(jìn)行計(jì)算的一個(gè)原因是,如果您只需要一點(diǎn)點(diǎn)信息,就不必將大量對(duì)象列表發(fā)送到設(shè)備。
例如,假設(shè)您正在編寫(xiě)一個(gè)讓人們?cè)u(píng)論電影的應(yīng)用程序。 單個(gè) ?Review
?對(duì)象可能如下所示:
{
"movie": "The Matrix",
"stars": 5,
"comment": "Too bad they never made any sequels."
}
如果您想查找 The Matrix 的平均星級(jí)數(shù),您可以查詢所有評(píng)論以及設(shè)備上的平均星級(jí)數(shù)。 但是,當(dāng)您只需要一個(gè)號(hào)碼時(shí),這會(huì)占用大量帶寬。 使用 ?Cloud Code
?,我們可以只傳遞電影的名稱,并返回平均星級(jí)。
?Cloud Functions
? 接受請(qǐng)求對(duì)象上的 JSON 參數(shù)字典,因此我們可以使用它來(lái)傳遞電影名稱。 整個(gè) ?Moralis JavaScript SDK
? 在云環(huán)境中可用,因此我們可以使用它來(lái)查詢 Review 對(duì)象。 實(shí)現(xiàn) averageStars 的代碼如下所示:
Moralis.Cloud.define("averageStars", async (request) => {
const query = new Moralis.Query("Review");
query.equalTo("movie", request.params.movie);
const results = await query.find();
let sum = 0;
for (let i = 0; i < results.length; ++i) {
sum += results[i].get("stars");
}
return sum / results.length;
});
使用 averageStars 和 hello 的唯一區(qū)別是我們必須在調(diào)用 ?Cloud Function
? 時(shí)提供將在 ?request.params.movie
? 中訪問(wèn)的參數(shù)。
以下包在 ?Cloud Function
? 代碼中全局可用,無(wú)需 ?require
?語(yǔ)句即可使用。
crypto
?(文檔)?Cloud Functions
? 不能有狀態(tài)。 他們可以讀取數(shù)據(jù)并將數(shù)據(jù)寫(xiě)入數(shù)據(jù)庫(kù),但您不能像下面的示例中那樣創(chuàng)建全局變量。
let name = "Satoshi"; // NOT ALLOWED
Moralis.Cloud.define("functionName", async (request) => {
let age = 20; // allowed
});
原因是您的云代碼將在您的服務(wù)器的許多實(shí)例之間實(shí)現(xiàn)負(fù)載平衡,以便 Moralis 可以無(wú)限擴(kuò)展您的應(yīng)用程序。
注意:服務(wù)器的不同實(shí)例不會(huì)共享在函數(shù)體之外定義的任何變量。
您的服務(wù)器的所有實(shí)例將共享同一個(gè)數(shù)據(jù)庫(kù)。 因此,如果您需要跨實(shí)例共享數(shù)據(jù),建議您將其存儲(chǔ)在數(shù)據(jù)庫(kù)中。
如果你創(chuàng)建全局變量,參考下面例子的結(jié)果
let count = 0; // very bad
Moralis.Cloud.define("increment", async (request) => {
logger.info(count);
count++;
});
// If you call the function above you may get the following results
// 0
// 0
// 0
// 1
// 1
// 2
// 1
// 3
// 0
// 2
因?yàn)槊看握?qǐng)求被隨機(jī)路由到服務(wù)器的不同實(shí)例并且每個(gè)實(shí)例都有自己?jiǎn)为?dú)的計(jì)數(shù)變量。
因此,我們希望您現(xiàn)在明白為什么不應(yīng)該使用全局變量。但是全局常量可以使用,因?yàn)樗鼈冎粫?huì)被復(fù)制到所有實(shí)例并且不會(huì)改變。
您可以使用?moralis-admin-cli
? 在您喜歡的IDE 中編寫(xiě)您的云函數(shù)。
首先,您需要通過(guò)在終端中運(yùn)行以下代碼來(lái)安裝它:
npm install -g moralis-admin-cli
安裝 ?Moralis Admin CLI
? 后,您可以前往管理面板并在您要使用的服務(wù)器上打開(kāi)云功能。
在模態(tài)框的下部,將有一個(gè)代碼片段,您需要在終端中運(yùn)行。
您唯一需要更改的是計(jì)算機(jī)上包含 ?Cloud Functions
? 的本地 JavaScript 文件夾的路徑。
moralis-admin-cli watch-cloud-folder --moralisApiKey your_api_key --moralisApiSecret your_api_secret --moralisSubdomain subdomain.moralis.io --autoSave 1 --moralisCloudfolder /path/to/cloud/folder
運(yùn)行命令后,每次保存都會(huì)在后端自動(dòng)更新云代碼!
出于調(diào)試或信息目的,打印消息通常很有用。 為此目的可以獲得一個(gè)記錄器。 它會(huì)將消息打印到 Moralis 儀表板的“Logs > info”部分。
const logger = Moralis.Cloud.getLogger();
logger.info("Hello World");
moralis-admin-cli get-logs --moralisApiKey MORALIS_CLI_API_KEY --moralisApiSecret MORALIS_CLI_SECRET_KEY
你可以通過(guò)?JS
?、?React
?來(lái)實(shí)現(xiàn)
const params = { movie: "The Matrix" };
const ratings = await Moralis.Cloud.run("averageStars", params);
// ratings should be 4.5
import { useMoralisCloudFunction } from "react-moralis";
function App() {
const { fetch } = useMoralisCloudFunction(
"averageStars",
{ movie: "The Moralis" },
{ autoFetch: false }
);
const cloudCall = () => {
fetch({
onSuccess: (data) => console.log(data), // ratings should be 4.5
});
};
return (
<button onClick={cloudCall}>Make Cloud Call</button>
);
}
export default App;
通常,會(huì)傳遞兩個(gè)參數(shù)給 Cloud Functions:
request
?- 請(qǐng)求對(duì)象包含有關(guān)請(qǐng)求的信息。 設(shè)置了以下字段:params
?- 參數(shù)對(duì)象由客戶端發(fā)送到函數(shù)。user
?- 發(fā)出請(qǐng)求的 ?Moralis.User
?。 如果沒(méi)有登錄用戶,則不會(huì)設(shè)置。如果函數(shù)成功,客戶端中的響應(yīng)如下所示:
{ "result": 4.8 }
如果出現(xiàn)錯(cuò)誤,客戶端中的響應(yīng)如下所示:
{
"code": 141,
"error": "movie lookup failed"
}
可以使用簡(jiǎn)單的 GET 請(qǐng)求直接調(diào)用 ?Cloud Functions
?。 將 Moralis 應(yīng)用程序 ID 和任何云函數(shù)參數(shù)作為查詢參數(shù)添加到 Moralis 服務(wù)器 URL。 假設(shè)您有以下云功能:
Moralis.Cloud.define("Hello", (request) => {
return `Hello ${request.params.name}! Cloud functions are cool!`
});
然后 URL 將如下所示:
https://1a2b3c4c5d6f.moralis.io:2053/server/functions/Hello?_ApplicationId=1a2b3c4c5d6f1a2b3c4c5d6f&name=CryptoChad
URL 具有以下結(jié)構(gòu):
?_ApplicationId=yourMoralisAppId
在需要主密鑰的請(qǐng)求中設(shè)置 ?useMasterKey:true
?。
示例:
query.find({useMasterKey:true});
object.save(null,{useMasterKey:true});
Moralis.Object.saveAll(objects,{useMasterKey:true});
注意:當(dāng)您使用 ?
useMasterKey:true
? 時(shí),默認(rèn)情況下可以在云功能中訪問(wèn)主密鑰
重要提示:不應(yīng)在您的前端代碼上使用主密鑰,因?yàn)樗梢栽谟脩舻臑g覽器中訪問(wèn)。
如果您使用來(lái)自您控制的另一個(gè)后端服務(wù)器的主密鑰,您可以使用以下代碼來(lái)初始化主密鑰:
const Moralis = require("moralis/node"); // Node.js
const appId = "YOUR_MORALIS_APP_ID";
const serverUrl = "YOUR_MORALIS_SERVER_URL";
const masterKey = "YOUR_MORALIS_MASTER_KEY";
Moralis.start({ serverUrl, appId, masterKey });
確保提供 ?Cloud Function
? 所需的參數(shù)并采用必要的格式非常重要。 您可以指定將在您的云函數(shù)之前調(diào)用的驗(yàn)證器函數(shù)或?qū)ο蟆?/p>
讓我們看一下averageStars的例子。 如果你想確保 ?request.params.movie
? 被提供,并且 averageStars 只能由登錄用戶調(diào)用,你可以在函數(shù)中添加一個(gè)驗(yàn)證器對(duì)象。
Moralis.Cloud.define("averageStars", async (request) => {
const query = new Moralis.Query("Review");
query.equalTo("movie", request.params.movie);
const results = await query.find();
let sum = 0;
for (let i = 0; i < results.length; ++i) {
sum += results[i].get("stars");
}
return sum / results.length;
},{
fields : ['movie'],
requireUser: true
});
如果不滿足驗(yàn)證器對(duì)象中指定的規(guī)則,云函數(shù)將不會(huì)運(yùn)行。 這意味著您可以自信地構(gòu)建您的函數(shù),知道 ?request.params.movie
? 以及 ?request.user
? 已定義。
通常,不僅定義 ?request.params.movie
? 很重要,而且它是正確的數(shù)據(jù)類型。 您可以通過(guò)為“驗(yàn)證器”中的字段參數(shù)提供一個(gè)對(duì)象來(lái)做到這一點(diǎn)。
Moralis.Cloud.define("averageStars", async (request) => {
const query = new Moralis.Query("Review");
query.equalTo("movie", request.params.movie);
const results = await query.find();
let sum = 0;
for (let i = 0; i < results.length; ++i) {
sum += results[i].get("stars");
}
return sum / results.length;
},{
fields : {
movie : {
required: true,
type: String,
options: val => {
return val.length < 20;
},
error: "Movie must be less than 20 characters"
}
},
requireUserKeys: {
accType : {
options: 'reviewer',
error: 'Only reviewers can get average stars'
}
}
});
此功能僅在以下情況下運(yùn)行:
request.params.movie
? 已定義。request.params.movie
? 是一個(gè)字符串。request.params.movie
? 少于 20 個(gè)字符。request.user
? 已定義。request.user.get('accType')
? 已定義。request.user.get('accType')
? 等于'reviewer'。完整的內(nèi)置驗(yàn)證選項(xiàng)包括:
requireMaster
?:函數(shù)是否需要?masterKey
?才能運(yùn)行。requireUser
?:函數(shù)是否需要 ?request.user
? 才能運(yùn)行。validateMasterKey
?:驗(yàn)證器是否應(yīng)該在 ?masterKey
?上運(yùn)行(默認(rèn)為 ?false
?)。fields
?:請(qǐng)求所需的字段的數(shù)組或?qū)ο蟆?/li>
requireUserKeys
?:要在 ?request.user
? 上驗(yàn)證的字段數(shù)組。?.fields
? 上的全部?jī)?nèi)置驗(yàn)證選項(xiàng)包括:
type
?:?request.params[field]
? 或 ?request.object.get(field)
? 的類型。default
?:如果該字段為空,則該字段應(yīng)默認(rèn)為什么。required
?:該字段是否為必填項(xiàng)。options
?:?jiǎn)蝹€(gè)選項(xiàng)、選項(xiàng)數(shù)組或字段允許值的自定義函數(shù)。constant
?:字段是否不可變。error
?:驗(yàn)證失敗時(shí)的自定義錯(cuò)誤消息。您還可以將函數(shù)傳遞給驗(yàn)證器。 這可以幫助您將重復(fù)出現(xiàn)的邏輯應(yīng)用于您的云代碼。
const validationRules = request => {
if (request.master) {
return;
}
if (!request.user || request.user.id !== 'masterUser') {
throw 'Unauthorized';
}
}
Moralis.Cloud.define('adminFunction', request => {
// do admin code here, confident that request.user.id is masterUser, or masterKey is provided
},validationRules)
Moralis.Cloud.define('adminFunctionTwo', request => {
// do admin code here, confident that request.user.id is masterUser, or masterKey is provided
},validationRules)
驗(yàn)證功能將在您的 ?Cloud Code Functions
? 之前運(yùn)行。 您可以在此處使用 ?async
?和 ?Promise
?,但盡量保持驗(yàn)證盡可能簡(jiǎn)單和快速,以便您的云請(qǐng)求快速解決。
如前所述,云驗(yàn)證器對(duì)象不會(huì)驗(yàn)證是否提供了主密鑰,除非設(shè)置了 ?validateMasterKey:true
?。 但是,如果您將驗(yàn)證器設(shè)置為函數(shù),則該函數(shù)將始終運(yùn)行。
Moralis 單位在您的云函數(shù)中可用。
為了成功運(yùn)行 units 函數(shù),您始終需要指定一個(gè)方法和一個(gè)值
將任何以太幣值轉(zhuǎn)換為 wei。
const result = await Moralis.Cloud.units({
method: "toWei",
value: 1
});
return result;
結(jié)果為: 1000000000000000000
將任何wei值轉(zhuǎn)換為ether。
const result = Moralis.Cloud.units({
method: "fromWei",
value: 1000000000000000
});
return result;
結(jié)果為: 0.001
將任何給定值轉(zhuǎn)換為其十六進(jìn)制表示。
const result = Moralis.Cloud.units({
method: "toHex",
value: 100
});
return result;
結(jié)果為: 64
使用自定義小數(shù)值轉(zhuǎn)換任何給定值。
result = Moralis.Cloud.units({
method: "fromWei",
value: 10000000000000,
decimals: 10
});
return result
結(jié)果為: 1000
Cloud Code 中提供了 Web3 功能,包括調(diào)用合約方法的能力。 Moralis 使用 Web3.js 和 ethers.js 庫(kù)。
// get a web3 instance for a specific chain
const web3 = Moralis.web3ByChain("0x1"); // mainnet
// get an ethers instance for a specific chain and ethersjs library
const web3 = Moralis.ethersByChain("0x4"); // rinkeby
當(dāng)您調(diào)用 ?Moralis.ethersByChain()
? 時(shí),您將獲得一個(gè)包含?provider
?和 ?ethers
?庫(kù)的對(duì)象。
{
provider: //A provider with the supplied chainId,
ethers: //ethers.js library,
}
通過(guò)為您希望連接的區(qū)塊鏈提供 ?chainId
?來(lái)請(qǐng)求 web3 對(duì)象。
注意: ?
Moralis.web3ByChain()
? 或 ?Moralis.ethersByChain()
? 返回的 web3 實(shí)例無(wú)法簽署交易。 有一種使用私鑰簽署交易的方法,但出于安全原因不建議這樣做。
以下是當(dāng)前支持的鏈列表。
Chain名稱 | ChainId |
Ethereum (Mainnet) | ?0x1 ? |
Ropsten (Ethereum Testnet) | ?0x3 ? |
Rinkeby | ?0x4 ? |
Goerli (Ethereum Testnet) | ?0x5 ? |
Kovan | ?0x2a ? |
Binance Smart Chain (Mainnet) | ?0x38 ? |
Binance Smart Chain (Testnet) | ?0x61 ? |
Matic (Mainnet) | ?0x89 ? |
Mumbai (Matic Testnet) | ?0x13881 ? |
Local Dev (Ganache, Hardhat) | ?0x539 ? |
一旦你有了一個(gè) web3 實(shí)例,你就可以通過(guò)使用 ?ABI
?和合約地址構(gòu)造一個(gè)合約實(shí)例來(lái)使用它來(lái)進(jìn)行合約調(diào)用。
const contract = new web3.eth.Contract(abi, address);
為方便起見(jiàn),Moralis 為 ERC20、ERC721 和 ERC1155 捆綁了 Openzepplin ABI。
Moralis.Web3.abis.erc20
?Moralis.Web3.abis.erc721
?Moralis.Web3.abis.erc1155
?把這一切放在一起...
const web3 = Moralis.web3ByChain("0x38"); // BSC
const abi = Moralis.Web3.abis.erc20;
const address = "0x...."
// create contract instance
const contract = new web3.eth.Contract(abi, address);
// get contract name
const name = await contract.methods
.name()
.call()
.catch(() => "");
有關(guān) Web3.js 合約接口的更多詳細(xì)信息,請(qǐng)參閱 Web3.js 文檔的 web3.eth.Contract 部分。
?Moralis.web3ByChain()
? 返回的 Web3 實(shí)例無(wú)法簽署交易。 在不久的將來(lái),可以使用自定義插件來(lái)做到這一點(diǎn)。 目前,如果您需要進(jìn)行鏈上合約交互,請(qǐng)考慮在前端執(zhí)行它們或創(chuàng)建一個(gè) NodeJS 后端,您可以在其中訪問(wèn)Truffle's HdWalletProvider。
要查找已在以太坊主網(wǎng)上發(fā)布的合約的 ?ABI
?,您可以通過(guò)搜索合約地址并查看“合約”選項(xiàng)卡來(lái)查看 Etherscan。 發(fā)布 ABI 的其他鏈也有類似的區(qū)塊瀏覽器。 例如,你可以去 BscScan 獲取 ?Binance Smart Chain
?。
對(duì)于你自己的合約,?ABI
?可以在編譯合約后的 build 目錄中找到
/truffle/build/contracts/myContract.json
/artifacts/contracts/myContract.sol/myContract.json
?通過(guò)使用?ethers
?:
const web3 = Moralis.ethersByChain("0x1")
var url = 'https://speedy-nodes-nyc.moralis.io/YOUR_ID_HERE/eth/mainnet';
var customHttpProvider = new web3.ethers.providers.JsonRpcProvider(url);
customHttpProvider.getBlockNumber().then((result) => {
logger.info("Current block number: " + result);
});
通過(guò)使用web3:
Moralis.Cloud.define("run_contract_function_with_web3", async (request) => {
web3 = new Moralis.Web3(new Moralis.Web3.providers.HttpProvider("https://speedy-nodes-nyc.moralis.io/YOUR_ID_HERE/bsc/mainnet"));
const abi = [{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"}]
address = "0x2170Ed0880ac9A755fd29B2688956BD959F933F8"
const contract = new web3.eth.Contract(abi, address)
const name = await contract.methods
.name()
.call()
.catch((e) => logger.error(`callName: ${e}${JSON.stringify(e, null, 2)}`))
return name;
});
IPFS 功能在您的云功能中可用。 為了成功上傳到 IPFS,您需要指定:
sourceType
?source
?以下是 ?sourceType
?支持的值
將給定 URL 的內(nèi)容推送到 IPFS。
const result = await Moralis.Cloud.toIpfs({
sourceType: "url",
source: "https://moralis.io/wp-content/uploads/2021/06/Moralis-Glass-Favicon.svg",
});
return result;
結(jié)果為:{ ?"path": "https://ipfs.moralis.io:2053/ipfs/QmYrUVhr1f6ZpZ4jrmi7mSv5X8MGjxxrgaERWde3cFASL6"
? }
將字符串推送到 IPFS。
const result = await Moralis.Cloud.toIpfs({
sourceType: "string",
source: "Moralis rules <3",
});
return result;
結(jié)果為: { ?"path": "https://ipfs.moralis.io:2053/ipfs/QmeYY26fCN4t2Apo9Nqix5ZDhJwcjoyDVLLz85TLkoiqpn"
? }
將對(duì)象推送到 IPFS。
const result = await Moralis.Cloud.toIpfs({
sourceType: 'object',
source: {
type: "Monster",
lp: 100,
spells: {
base: ["spell one","spell two"],
locked: ["spell three"],
}
},
});
return result;
結(jié)果為: { ?"path": "https://ipfs.moralis.io:2053/ipfs/QmWowsJ74rYCHUYhag83Puky1qZTSsdj3n7bT2ejE2NvCJ"
? }
將 base64 文件推送到 IPFS。
const result = await Moralis.Cloud.toIpfs({
sourceType: "base64Binary",
source: "/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoGCBETExcTEhETGBcYFxkaGBkZGRkZG",
});
return result;
結(jié)果為: { ?"path": "https://ipfs.moralis.io:2053/ipfs/QmaZRSn8cHKUN5LsvuY6M8a5LzV76uFKeZ9khthPj2rHhw"
?}
將 base64 字符串推送到 IPFS。
const result = await Moralis.Cloud.toIpfs({
sourceType: "base64",
source: "TW9yYWxpcyBydWxlcyA8Mw=="
});
return result;
結(jié)果為: { ?"path": "https://ipfs.moralis.io:2053/ipfs/QmeYY26fCN4t2Apo9Nqix5ZDhJwcjoyDVLLz85TLkoiqpn"
? }
更多建議: