首页指南参考教程

Webhook

了解如何配置 Webhooks 以获取有关 EAS 构建和 EAS 提交完成的警报。


一旦你的构建或提交完成,EAS 就会通过 Webhook 向你发出提醒。需要为每个项目配置 Webhook。例如,如果你想在每个目录中收到 @johndoe/awesomeApp@johndoe/coolApp 的警报,请运行以下命令:

¥EAS can alert you as soon as your build or submission is completed via a webhook. Webhooks need to be configured per project. For example, if you want to be alerted for both @johndoe/awesomeApp and @johndoe/coolApp, in each directory, run the command:

Terminal
eas webhook:create

运行后,系统将提示你选择 Webhook 事件类型(除非你提供 --event BUILD|SUBMIT 参数)。接下来,提供处理 HTTP POST 请求的 Webhook URL(或使用 --url 标志指定)。此外,如果你尚未提供 --secret 标志,则必须输入 Webhook 签名密钥。它的长度必须至少为 16 个字符,并将用于计算我们作为 expo-signature HTTP 标头的值发送的请求正文的签名。你可以使用 用于验证 Webhook 请求的签名 是正品。

¥After running it, you'll be prompted to choose the webhook event type (unless you provide the --event BUILD|SUBMIT parameter). Next, provide the webhook URL (or specify it with the --url flag) that handles HTTP POST requests. Additionally, you'll have to input a webhook signing secret, if you have not already provided it with the --secret flag. It must be at least 16 characters long, and it will be used to calculate the signature of the request body which we send as the value of the expo-signature HTTP header. You can use the signature to verify a webhook request is genuine.

EAS 使用 HTTP POST 请求调用你的 Webhook。所有数据都在请求正文中传递。EAS 将数据作为 JSON 对象发送。如果 webhook 响应的 HTTP 状态代码超出 200-399 范围,则将尝试以指数回退方式多次传送。

¥EAS calls your webhook using an HTTP POST request. All the data is passed in the request body. EAS sends the data as a JSON object. If the webhook responds with an HTTP status code outside of the 200-399 range, delivery will be attempted a few more times with exponential back-off.

此外,我们还发送带有有效负载哈希签名的 expo-signature HTTP 标头。你可以使用此签名来验证请求的真实性。签名是请求正文的十六进制编码的 HMAC-SHA1 摘要,使用你的 Webhook 密钥作为 HMAC 密钥。

¥Additionally, we send an expo-signature HTTP header with the hash signature of the payload. You can use this signature to verify the authenticity of the request. The signature is a hex-encoded HMAC-SHA1 digest of the request body, using your webhook secret as the HMAC key.

如果你想在本地测试上述 Webhook,你可以使用 ngrok 等服务通过隧道转发 localhost:8080,并通过 ngrok 提供的 URL 公开访问它。

¥If you want to test the above webhook locally, you can use a service such as ngrok to forward localhost:8080 via a tunnel and make it publicly accessible with the URL ngrok gives you.

你始终可以通过运行命令来更改你的 webhook URL 和/或 webhook 密钥:

¥You can always change your webhook URL and/or webhook secret by running command:

Terminal
eas webhook:update --id WEBHOOK_ID

你可以通过运行以下命令找到 webhook ID:

¥You can find the webhook ID by running the command:

Terminal
eas webhook:list

如果你希望我们停止向你的 Webhook 发送请求,请运行以下命令并从列表中选择 Webhook:

¥If you want us to stop sending requests to your webhook, run the command below and choose the webhook from the list:

Terminal
eas webhook:delete

Webhook 负载

¥Webhook payload

Build webhook payload

构建 Webhook 有效负载可能如下例所示:

¥The build webhook payload may look as the example below:

{
  "id": "147a3212-49fd-446f-b4e3-a6519acf264a",
  "accountName": "dsokal",
  "projectName": "example",
  "buildDetailsPageUrl": "https://expo.dev/accounts/dsokal/projects/example/builds/147a3212-49fd-446f-b4e3-a6519acf264a",
  "parentBuildId": "75ac0be7-0d90-46d5-80ec-9423fa0aaa6b", // available for build retries
  "appId": "bc0a82de-65a5-4497-ad86-54ff1f53edf7",
  "initiatingUserId": "d1041496-1a59-423a-8caf-479bb978203a",
  "cancelingUserId": null, // available for canceled builds
  "platform": "android", // or "ios"
  "status": "errored", // or: "finished", "canceled"
  "artifacts": {
    "buildUrl": "https://expo.dev/artifacts/eas/wyodu9tua2ZuKKiaJ1Nbkn.aab", // available for successful builds
    "logsS3KeyPrefix": "production/f9609423-5072-4ea2-a0a5-c345eedf2c2a"
  },
  "metadata": {
    "appName": "example",
    "username": "dsokal",
    "workflow": "managed",
    "appVersion": "1.0.2",
    "appBuildVersion": "123",
    "cliVersion": "0.37.0",
    "sdkVersion": "41.0.0",
    "buildProfile": "production",
    "distribution": "store",
    "appIdentifier": "com.expo.example",
    "gitCommitHash": "564b61ebdd403d28b5dc616a12ce160b91585b5b",
    "gitCommitMessage": "Add home screen",
    "runtimeVersion": "1.0.2",
    "channel": "default", // available for EAS Update
    "releaseChannel": "default", // available for legacy updates
    "reactNativeVersion": "0.60.0",
    "trackingContext": {
      "platform": "android",
      "account_id": "7c34cbf1-efd4-4964-84a1-c13ed297aaf9",
      "dev_client": false,
      "project_id": "bc0a82de-65a5-4497-ad86-54ff1f53edf7",
      "tracking_id": "a3fdefa7-d129-42f2-9432-912050ab0f10",
      "project_type": "managed",
      "dev_client_version": "0.6.2"
    },
    "credentialsSource": "remote",
    "isGitWorkingTreeDirty": false,
    "message": "release build", // message attached to the build
    "runFromCI": false
  },
  "metrics": {
    "memory": 895070208,
    "buildEndTimestamp": 1637747861168,
    "totalDiskReadBytes": 692224,
    "buildStartTimestamp": 1637747834445,
    "totalDiskWriteBytes": 14409728,
    "cpuActiveMilliseconds": 12117.540078,
    "buildEnqueuedTimestamp": 1637747792476,
    "totalNetworkEgressBytes": 355352,
    "totalNetworkIngressBytes": 78781667
  },
  // available for failed builds
  "error": {
    "message": "Unknown error. Please see logs.",
    "errorCode": "UNKNOWN_ERROR"
  },
  "createdAt": "2021-11-24T09:53:01.155Z",
  "enqueuedAt": "2021-11-24T09:53:01.155Z",
  "provisioningStartedAt": "2021-11-24T09:54:01.155Z",
  "workerStartedAt": "2021-11-24T09:54:11.155Z",
  "completedAt": "2021-11-24T09:57:42.715Z",
  "updatedAt": "2021-11-24T09:57:42.715Z",
  "expirationDate": "2021-12-24T09:53:01.155Z",
  "priority": "high", // or: "normal", "low"
  "resourceClass": "android-n2-1.3-12",
  "actualResourceClass": "android-n2-1.3-12",
  "maxRetryTimeMinutes": 3600 // max retry time for failed/canceled builds
}
Submit webhook payload

提交 Webhook 负载可能如下例所示:

¥The submit webhook payload may look as the example below:

{
  "id": "0374430d-7776-44ad-be7d-8513629adc54",
  "accountName": "dsokal",
  "projectName": "example",
  "submissionDetailsPageUrl": "https://expo.dev/accounts/dsokal/projects/example/builds/0374430d-7776-44ad-be7d-8513629adc54",
  "parentSubmissionId": "75ac0be7-0d90-46d5-80ec-9423fa0aaa6b", // available for submission retries
  "appId": "23c0e405-d282-4399-b280-5689c3e1ea85",
  "archiveUrl": "http://archive.url/abc.apk",
  "initiatingUserId": "7bee4c21-3eaa-4011-a0fd-3678b6537f47",
  "cancelingUserId": null, // available for canceled submissions
  "turtleBuildId": "8c84111e-6d39-449c-9895-071d85fd3e61", // available when submitting a build from EAS
  "platform": "android", // or "ios"
  "status": "errored", // or: "finished", "canceled"
  "submissionInfo": {
    // available for failed submissions
    "error": {
      "message": "Android version code needs to be updated",
      "errorCode": "SUBMISSION_SERVICE_ANDROID_OLD_VERSION_CODE_ERROR"
    },
    "logsUrl": "https://submission-service-logs.s3-us-west-1.amazonaws.com/production/submission_728aa20b-f7a9-4da7-9b64-39911d427b19.txt"
  },
  "createdAt": "2021-11-24T10:15:32.822Z",
  "updatedAt": "2021-11-24T10:17:32.822Z",
  "completedAt": "2021-11-24T10:17:32.822Z",
  "maxRetryTimeMinutes": 3600 // max retry time for failed/canceled submissions
}

Webhook 服务器

¥Webhook server

以下是如何实现服务器的示例:

¥Here's an example of how you can implement your server:

server.js
const crypto = require('crypto');
const express = require('express');
const bodyParser = require('body-parser');
const safeCompare = require('safe-compare');

const app = express();
app.use(bodyParser.text({ type: '*/*' }));
app.post('/webhook', (req, res) => {
  const expoSignature = req.headers['expo-signature'];
  // process.env.SECRET_WEBHOOK_KEY has to match SECRET value set with `eas webhook:create` command
  const hmac = crypto.createHmac('sha1', process.env.SECRET_WEBHOOK_KEY);
  hmac.update(req.body);
  const hash = `sha1=${hmac.digest('hex')}`;
  if (!safeCompare(expoSignature, hash)) {
    res.status(500).send("Signatures didn't match!");
  } else {
    // Do something here.  For example, send a notification to Slack!
    // console.log(req.body);
    res.send('OK!');
  }
});
app.listen(8080, () => console.log('Listening on port 8080'));
Expo 中文网 - 粤ICP备13048890号