Webhook 是发生某事时发生的 HTTP回调;一个通过 HTTP post 的简单事件通知系统,允许开发人员轻松访问支付活动的通知,例如支付状态更新或重复收费。处理完每个通知后,您可以在后端执行操作,例如:
通过电子邮件将购买确认信息发送给您的客户。
启用数字媒体的下载。
发出退款。
跟踪哪些订阅处于活动状态。
要创建 Webhook,请导航到 PayPal Dashboard,然后单击My Apps & Credentials。然后选择要在其中设置 Webhook 的应用程序。
您可以查看有关您的应用程序的详细信息。注意右上角有两个按钮(Sandbox、Live),在本教程中我将使用Sandbox ,但您需要在开始 Live 之前设置 Live 设置。要为此应用程序配置 Webhook,请单击屏幕截图中显示的添加 Webhook:
选择您希望收到通知的事件类型,然后输入Webhook将被发送到的 URL(它必须是 HTTPS)。为了处理 Webhook 调用,我将向 HomeController 添加一个名为“Webhook”的新操作方法:
public IActionResult Webhook() { // TODO: Handle Webhook call }
所以这种情况下的 Webhook Url 将是:https://pedroalonso.localtunnel.me/home/webhook。我将在下一节解释“localtunnel”部分。
保存 Webhook 后,您将看到以下确认屏幕:
现在 Webhook 已设置好,您可以在左侧菜单中的“Webhooks Simulator”下看到,在这里您可以将“test”webhook 事件发送到您的 URL 以测试您的代码是否正常工作。此外,在“Webhooks 事件”下,您可以看到 PayPal 为该应用程序发送的所有事件。如果要进行进一步测试,您可以验证您是否正确处理了事件并重新发送它们。
为了了解 Webhook 是如何工作的,我运行了我们在上一个教程中构建的项目,并创建了一个“授权付款并稍后捕获”,以便 PayPal 发送事件。运行示例后,我点击了“Webhooks event”,可以看到该事件已发送:
如您所见,如果您想调试代码并查看如何正确实现处理程序,则在右侧有一个Resend按钮。此外,如果您单击该事件,您可以看到所有详细信息:
这是 Webhook 事件的完整 JSON:
{ "id": "WH-9U51749144910293K-8LX80763BC1567402", "create_time": "2016-01-19T17:50:30Z", "resource_type": "sale", "event_type": "PAYMENT.SALE.COMPLETED", "summary": "Payment completed for $ 100.0 USD", "resource": { "amount": { "total": "100.00", "currency": "USD", "details": { "subtotal": "100.00", "tax": "15.00", "shipping": "10.00" } }, "id": "73G8209522783053E", "parent_payment": "PAY-7MB27930V5981832YK2PHN7Q", "update_time": "2016-01-19T17:49:05Z", "create_time": "2016-01-19T17:49:05Z", "payment_mode": "INSTANT_TRANSFER", "state": "completed", "links": [ { "href": "https://api.sandbox.paypal.com/v1/payments/sale/73G8209522783053E", "rel": "self", "method": "GET" }, { "href": "https://api.sandbox.paypal.com/v1/payments/sale/73G8209522783053E/refund", "rel": "refund", "method": "POST" }, { "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAY-7MB27930V5981832YK2PHN7Q", "rel": "parent_payment", "method": "GET" } ], "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": { "value": "3.20", "currency": "USD" }, "protection_eligibility": "ELIGIBLE" }, "status": "PENDING", "transmissions": [ { "webhook_url": "https://pedroalonso.localtunnel.me/home/webhook", "response_headers": { "Date": "Wed, 20 Jan 2016 12:53:51 GMT", "Content-Length": "53", "HTTP/1.1 502 Bad Gateway": "", "SERVER_INFO": "", "Connection": "keep-alive", "Server": "nginx/1.7.8" }, "transmission_id": "218dc9c0-bed5-11e5-927f-6b62a8a99ac4", "status": "PENDING", "timestamp": "2016-01-19T17:50:30Z" } ], "links": [ { "href": "https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-9U51749144910293K-8LX80763BC1567402", "rel": "self", "method": "GET", "encType": "application/json" }, { "href": "https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-9U51749144910293K-8LX80763BC1567402/resend", "rel": "resend", "method": "POST", "encType": "application/json" } ] }
正如您在图片中看到的,事件详细信息以 JSON 编码,并作为请求正文发送到您的 Webhook URL 处理程序。此外,我们需要在处理程序中使用几个重要的属性:
id :这是 webhook 事件的 id,如果我们要检索特定的 webhook 事件,我们需要将此参数发送到PayPal。
event_type:这用于了解我们正在接收的事件类型,因为我们可能需要以不同的方式处理不同的事件类型。
resource.parent_payment:这是与此事件相关的付款的 ID。我们可能将此 id 存储在数据库中,并且可以向我们的客户发送电子邮件或运送客户购买的商品。
根据前面的解释,这是动作控制器处理 Webhook 的代码:
public IActionResult Webhook() { // The APIContext object can contain an optional override for the trusted certificate. var apiContext = PayPalConfiguration.GetAPIContext(); // Get the received request's headers var requestheaders = HttpContext.Request.Headers; // Get the received request's body var requestBody = string.Empty; using (var reader = new System.IO.StreamReader(HttpContext.Request.Body)) { requestBody = reader.ReadToEnd(); } dynamic jsonBody = JObject.Parse(requestBody); string webhookId = jsonBody.id; var ev = WebhookEvent.Get(apiContext, webhookId); // We have all the information the SDK needs, so perform the validation. // Note: at least on Sandbox environment this returns false. // var isValid = WebhookEvent.ValidateReceivedEvent(apiContext, ToNameValueCollection(requestheaders), requestBody, webhookId); switch (ev.event_type) { case "PAYMENT.CAPTURE.COMPLETED": // Handle payment completed break; case "PAYMENT.CAPTURE.DENIED": // Handle payment denied break; // Handle other webhooks default: break; } return new HttpStatusCodeResult(200); }
有几件事要从前面的函数中解释。从第 10-16 行开始,我只读取请求的正文并将 JSON 对象解析为动态 C# 对象。在第 18 行(可选)上,我使用事件 ID 调用 PayPal API 以获取完整的事件详细信息。这样做是为了安全,以验证我使用的是有效的 PayPal 对象。在第 24 行,我创建了一个开关来评估我想要处理的 Webhook 的类型,并根据需要编写自定义代码。
您还可以看到,第 22 行被注释掉了。显然,该方法验证请求中的 SSL 证书有效并且属于 PayPal,但它在沙盒模式下不起作用。它可能在 Live 中工作,但我不喜欢在 Live 中有未经测试的代码,特别是如果它正在处理支付网关,所以我选择删除它并使用不同的方法。如果您使用 PayPal SDK 库的php版本,请记住函数 'ValidateReceivedEvent' 甚至不存在。
测试 Webhook:安全隧道
如您之前所见,为了测试 Webhook,我们需要配置一个公共 URL,PayPal 可以使用该 URL 来发送事件。如果我们在本地工作,通常我们使用'localhost'进行开发,所以这将是一个小问题。为了解决这个问题,我们需要为我们的本地计算机配置一个安全隧道。
Localtunnel是一个小软件,可以在您的本地机器和可公开访问的域之间创建安全隧道。它对于测试 Webhook 很有用,但您也可以使用它来将实时 URL 共享到在您的开发机器上运行的 Web 应用程序,以用于测试、反馈或其他任务。
你需要有node.js 才能安装 localtunnel。然后只需打开控制台或终端,然后运行:
$ npm install -g localtunnel
要创建隧道,请运行:
$ lt --port 5000 --subdomain pedroalonso
这会将 URL ' https://pedroalonso.localtunnel.me ' 映射到 'localhost:5000'。如果您在 IIS Express 上运行项目,您可能会使用不同的端口,因此您需要在命令中反映这一点。
在设置 localtunnel 并且我们的项目正在运行后,我在 Visual Studio 中添加了一个断点来评估我得到的数据。如您在此屏幕截图中所见,我已将 JSON 事件对象映射到 C# 动态对象。
使用事件 ID 从 PayPal API 检索事件,我们还可以获取事件详细信息,如您在此处看到的:
结论
Webhook 正在成为 rest API 通知应用程序有关事件的标准方式。如您所见,它们非常容易处理,并且被许多公司使用,例如 Stripe、SendGrid、mailchimp等。PayPal 曾经有即时付款通知,现在仍在使用,但他们建议尽可能实施 Webhook .