# 使用 Webhook 处理支付事件 如何用 Webhook 响应离线支付事件。 *Webhook* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests) 是一个 HTTP 端点,用于从 Stripe 接收事件。 通过 Webhook,您可以接收付款流程以外发生的支付事件的通知,例如: - 成功付款 (`payment_intent.succeeded`) - 有争议的付款 (`charge.dispute.created`) - Stripe 账户可用余额 (`balance.available`) 您可以使用管理平台进行一次性操作,例如退款或更新客户信息,尽管 Webhook 可以扩展您的支付集成和处理大量重要业务事件。 ## 构建您自己的 Webhook 可在自己的服务器上构建一个 Webhook 处理程序,用以管理您的所有线下付款流程。首先公开一个可以接收 Stripe 的请求的端点并用 CLI 在本地测试您的集成。来自 Stripe 的每个请求都会包含一个 [Event](https://docs.stripe.com/api/events/object.md) 对象,其中引用了 Stripe 上修改的对象。 ## 创建 Webhook 端点 在您的应用中添加新端点。您可通过检查请求体内发送的事件对象的 `type` 字段来操作某些事件。然后,您可以通过标准输出打印,确保您的 Webhook 能正常工作。 添加完新的端点后启动服务器。 #### Java ```java // Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. // Find your keys at https://dashboard.stripe.com/apikeys. StripeClient stripeClient = new StripeClient("<>"); import com.stripe.StripeClient; import com.stripe.model.StripeObject; import com.stripe.net.ApiResource; import com.stripe.model.Event; import com.stripe.model.EventDataObjectDeserializer; import com.stripe.model.PaymentIntent; // Using the Spark framework public Object handle(Request request, Response response) { String payload = request.body(); Event event = null; try { event = ApiResource.GSON.fromJson(payload, Event.class); } catch (JsonSyntaxException e) { // Invalid payload response.status(400); return ""; } // Deserialize the nested object inside the event EventDataObjectDeserializer dataObjectDeserializer = event.getDataObjectDeserializer(); StripeObject stripeObject = null; if (dataObjectDeserializer.getObject().isPresent()) { stripeObject = dataObjectDeserializer.getObject().get(); } else { // Deserialization failed, probably due to an API version mismatch. // Refer to the Javadoc documentation on `EventDataObjectDeserializer` for // instructions on how to handle this case, or return an error here. } // Handle the event switch (event.getType()) { case "payment_intent.succeeded": PaymentIntent paymentIntent = (PaymentIntent) stripeObject; System.out.println("PaymentIntent was successful!"); break; case "payment_method.attached": PaymentMethod paymentMethod = (PaymentMethod) stripeObject; System.out.println("PaymentMethod was attached to a Customer!"); break; // ... handle other event types default: System.out.println("Unhandled event type: " + event.getType()); } response.status(200); return ""; } ``` ## 安装并设置 Stripe CLI 如需更多安装选项,请查看[用 Stripe CLI 开始](https://docs.stripe.com/stripe-cli.md)。 如果您安装着 Stripe CLI,则在命令行中运行 `stripe login`,生成一个配对代码来关联到您的 Stripe 账户。按**回车**启动浏览器,登入您的 Stripe 账户来允许访问。生成的 API 有效期为 90 天。可在管理平台的 [API 密钥](https://dashboard.stripe.com/apikeys)下修改或删除密钥。 > 您可以创建项目特定的配置,方法是在登录时和运行该项目的命令时包含 [–project-name](https://docs.stripe.com/cli/login#login-project-name) 标志。 测试 ```bash stripe login Your pairing code is: humour-nifty-finer-magic Press Enter to open up the browser (^C to quit) ``` 如果要使用现有的 API 密钥,则使用 `--api-key` 标志: ```bash stripe login --api-key <> Your pairing code is: humour-nifty-finer-magic Press Enter to open up the browser (^C to quit) ``` ## 在本地测试您的 Webhook 通过 `listen` 指令,用 CLI 将事件转到您的本地 Webhook 端点。 假设您的应用的运行端口是 4242,运行: ```bash stripe listen --forward-to http://localhost:4242/webhook ``` 在另一个终端选项卡中,用 `trigger` CLI 指令触发一个模拟 Webhook 事件。 ```bash stripe trigger payment_intent.succeeded ``` 您的 `listen` 选项卡中会显示以下事件: ```bash [200 POST] OK payment_intent.succeeded ``` “PaymentIntent 已成功!”出现在您的服务器运行的终端选项卡中。 ## Optional: 检查 Webhook 签名 Stripe 在每个事件的 `Stripe-Signature` 头内都包含了一个签名。这样可表示事件是由 Stripe 发送的,而非第三方。要验证签名,可以使用我们的官方库,也可以用您自己的方案[手动验证签名](https://docs.stripe.com/webhooks.md#verify-manually)。 首先,找出您的 Webhook 端点密钥并将它作为 `endpoint_secret` 添加到您的 Webhook 处理程序。由于您仍在用 Stripe CLI 在本地部署您的端点,因此需要用 `trigger` 命令从 CLI 获取 Webhook 端点密钥。 ```bash stripe listen ``` Webhook 端点密钥以 `whsec_` 开头,后跟一串数字和字母。妥善保管此 Webhook 端点,切勿公开。 #### Java ```java import com.stripe.Stripe; import com.stripe.model.StripeObject; import com.stripe.net.ApiResource; import com.stripe.model.Event; import com.stripe.model.EventDataObjectDeserializer; import com.stripe.model.PaymentIntent; import com.stripe.exception.SignatureVerificationException; // If you are testing your webhook locally with the Stripe CLI you // can find the endpoint's secret by running `stripe listen` // Otherwise, find your endpoint's secret in your webhook settings in the Developer DashboardString endpointSecret = "whsec_...";//Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.//Find your keys at https://dashboard.stripe.com/apikeys.StripeClient stripeClient = new StripeClient("<>"); // Using the Spark framework public Object handle(Request request, Response response) { String payload = request.body();String sigHeader = request.headers("Stripe-Signature"); Event event = null; try {event = stripeClient.constructEvent( payload, sigHeader, endpointSecret ); } catch (JsonSyntaxException e) { // Invalid payload System.out.println("Error parsing payload: " + e.getMessage()); response.status(400); return gson.toJson(new ErrorResponse(e.getMessage()));} catch (SignatureVerificationException e) { // Invalid signature System.out.println("Error verifying webhook signature: " + e.getMessage()); response.status(400); return gson.toJson(new ErrorResponse(e.getMessage())); } // Deserialize the nested object inside the event EventDataObjectDeserializer dataObjectDeserializer = event.getDataObjectDeserializer(); StripeObject stripeObject = null; if (dataObjectDeserializer.getObject().isPresent()) { stripeObject = dataObjectDeserializer.getObject().get(); } else { // Deserialization failed, probably due to an API version mismatch. // Refer to the Javadoc documentation on `EventDataObjectDeserializer` for // instructions on how to handle this case, or return an error here. } // Handle the event switch (event.getType()) { case "payment_intent.succeeded": PaymentIntent paymentIntent = (PaymentIntent) stripeObject; System.out.println("PaymentIntent was successful!"); break; case "payment_method.attached": PaymentMethod paymentMethod = (PaymentMethod) stripeObject; System.out.println("PaymentMethod was attached to a Customer!"); break; // ... handle other event types default: System.out.println("Unhandled event type: " + event.getType()); } response.status(200); return ""; } ``` ## 部署您的 Webhook 端点 准备好将 Webhook 端点部署到生产时,您需要进行以下操作: 1. 使用您的[真实模式 API 密钥](https://docs.stripe.com/keys.md#test-live-modes),不要使用测试模式的密钥。 1. 在 [Workbench](https://docs.stripe.com/workbench.md) 中或通过 API 配置 Webhook 端点。 1. 要在 Workbench 中配置端点,请转到 [Webhook 选项卡](https://dashboard.stripe.com/workbench/webhooks)。 1. 点击**添加目标**,然后输入 Stripe API 版本和您希望 Stripe 发送的特定事件。点击**继续**,然后从可用目标类型列表中选择 **Webhook 端点**。点击**继续**,然后输入端点的 URL、可选名称和可选描述。点击 **创建目标**。 1. 将应用程序中的 Webhook 端点密钥替换为 Workbench 的目标详情视图中为端点显示的新密钥。 您的应用现在可以进行真实事件了。有关配置 Webhook 端点的详细信息,请参阅 [Webhook Endpoint](https://docs.stripe.com/api/webhook_endpoints.md) API。要在沙盒中进行测试,[请参阅我们的开发指南](https://docs.stripe.com/webhooks.md)。