使用 ngrok 和 Express(節點)測試 Sandbox Webhooks
在這個例子中,我們將討論在沙盒中測試 webhook 通知,使用 ngrok 為我們的 Node HTTP 偵聽器提供隧道,在 localhost 上執行到 Internet。對於此示例,我們將使用 Node 為付款事件設定通知 webhook(例如正在進行付款),然後設定伺服器以偵聽來自 webhook 事件的傳入 HTTP POST 訊息。
我們將在此處執行以下幾個步驟來實現此目的:
- 設定一個簡單的伺服器來監聽來自 webhooks 的傳入 POST 流量,這將是來自 PayPal 的通知,並開始偵聽 localhost。
- 然後使用 ngrok 提供從 localhost 到 Internet 的隧道,以便 PayPal 可以釋出通知。
- 最後,將我們的應用程式(基於提供的憑據)訂閱到我們要跟蹤的 webhook 事件,從步驟 2 提供公共 ngrok URI。
建立 Webhooks 監聽器
我們需要做的第一件事就是建立監聽器。我們開始使用監聽器的原因是因為我們需要 ngrok 實時 URL 在建立或更新時提供給 webhook。
var bodyParser = require('body-parser'),
http = require('http'),
app = require('express')();
app.use(bodyParser.json());
app.post('/', function(req, res){
console.log(JSON.stringify(req.body));
});
//create server
http.createServer(app).listen(3001, function () {
console.log('Server started: Listening on port 3001');
});
我們的聽眾是使用 Express 的簡單路線。我們監聽任何傳入的 POST 流量,然後將 POST 主體吐出到控制檯。我們可以使用它來做任何我們喜歡的聽眾。
當我們在最後建立 HTTP 伺服器時,我們將其設定為偵聽 localhost 埠 3001.現在執行該指令碼以開始偵聽流量。
使用 ngrok 將監聽器暴露給 Internet
在 localhost:3001 上設定監聽器,我們的下一個工作是將該指令碼暴露給網際網路,以便可以將流量傳送給它,這是 ngrok 的工作。
從終端視窗執行以下命令:
ngrok http 3001
這將啟動在埠 3001 上為 localhost 提供實時隧道的過程,並在執行後提供以下資訊:
http://i.stack.imgur.com/UVwad.jpg
我們可以看到,我們可以用來將 PayPal webhook 指向我們在 localhost 上執行的監聽器的實時地址是 http(s)://055b3480.ngrok.io
。這就是我們設定監聽器所需要知道的全部內容。
訂閱通知
我們的最後一步是為我們的應用程式建立 webhooks,當我們的應用程式上的付款,退款等發生某些事件時,它會建立通知。我們只需建立一次這些 webhook 就可以將它們繫結到應用程式,因此每次要使用它們時都不需要執行它們。
首先,我們通過新增 PayPal Node SDK 的要求,建立應用程式的客戶端 ID /機密,然後為沙箱配置環境來設定 PayPal 環境。
var paypal = require('paypal-rest-sdk');
var clientId = 'YOUR APPLICATION CLIENT ID';
var secret = 'YOUR APPLICATION SECRET';
paypal.configure({
'mode': 'sandbox', //sandbox or live
'client_id': clientId,
'client_secret': secret
});
接下來,我們為 webhooks 設定 JSON 結構。webhooks
包含兩條資訊,即應該傳送所有 webhook 事件的 url
,以及我們想要訂閱的 event_types
。
對於此示例,url
設定為我們的 ngrok 實時 URL,我們正在偵聽的事件是完成或拒絕付款的情況。
有關潛在事件的完整列表,請參閱 https://developer.paypal.com/docs/integration/direct/rest-webhooks-overview/#event-type-support 。
最後,我們將 webhooks
物件傳遞給呼叫以建立 webhooks,notification.webhook.create
。如果成功,PayPal 將向我們指定的端點傳送通知,該端點在 localhost 上執行。
var webhooks = {
"url": "https://436e4d13.ngrok.io",
"event_types": [{
"name": "PAYMENT.SALE.COMPLETED"
},{
"name": "PAYMENT.SALE.DENIED"
}
]};
paypal.notification.webhook.create(webhooks, function (err, webhook) {
if (err) {
console.log(err.response);
throw error;
} else {
console.log("Create webhook Response");
console.log(webhook);
}
});
一旦我們使用這些應用程式憑據發出付款,有關付款狀態的資訊將傳送到我們設定的端點。
PayPal 作為通知傳送的 POST 正文的示例可能如下所示,這是在成功支付 PayPal 後傳送的:
{
"id": "WH-9FE9644311463722U-6TR22899JY792883B",
"create_time": "2016-04-20T16:51:12Z",
"resource_type": "sale",
"event_type": "PAYMENT.SALE.COMPLETED",
"summary": "Payment completed for $ 7.47 USD",
"resource": {
"id": "18169707V5310210W",
"state": "completed",
"amount": {
"total": "7.47",
"currency": "USD",
"details": {
"subtotal": "7.47"
}
},
"payment_mode": "INSTANT_TRANSFER",
"protection_eligibility": "ELIGIBLE",
"protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE",
"transaction_fee": {
"value": "0.52",
"currency": "USD"
},
"invoice_number": "",
"custom": "",
"parent_payment": "PAY-809936371M327284GK4L3FHA",
"create_time": "2016-04-20T16:47:36Z",
"update_time": "2016-04-20T16:50:07Z",
"links": [
{
"href": "https:\/\/api.sandbox.paypal.com\/v1\/payments\/sale\/18169707V5310210W",
"rel": "self",
"method": "GET"
},
{
"href": "https:\/\/api.sandbox.paypal.com\/v1\/payments\/sale\/18169707V5310210W\/refund",
"rel": "refund",
"method": "POST"
},
{
"href": "https:\/\/api.sandbox.paypal.com\/v1\/payments\/payment\/PAY-809936371M327284GK4L3FHA",
"rel": "parent_payment",
"method": "GET"
}
]
},
"links": [
{
"href": "https:\/\/api.sandbox.paypal.com\/v1\/notifications\/webhooks-events\/WH-9FE9644311463722U-6TR22899JY792883B",
"rel": "self",
"method": "GET"
},
{
"href": "https:\/\/api.sandbox.paypal.com\/v1\/notifications\/webhooks-events\/WH-9FE9644311463722U-6TR22899JY792883B\/resend",
"rel": "resend",
"method": "POST"
}
]
}