wordpress 如何在Xero Webhook中向Xero API提交Post请求

mwkjh3gx  于 2023-10-17  发布在  WordPress
关注(0)|答案(1)|浏览(110)

我有一个Webhook在我的Xero帐户上为你服务。当一个新的发票被创建时,我想使用Webhook中的数据访问Xero API,向用户发送发票电子邮件。我有所有的代码,但我的问题是,Webhook期望响应200,当我从webhook内部调用Xero API代码时,我在Xero上得到一个错误,说响应包含一个body。这是有意义的,因为我提交并从API获取数据。
那么,我如何向Xero API发出请求而不干扰Xero Webhook响应呢?
Webhook代码:

<?php
    ///////////////////////////////////////////////////////////////////////////
    // WEBHOOK AUTHENTICATION - START
    ///////////////////////////////////////////////////////////////////////////
    //hook section
    $rawPayload = file_get_contents("php://input");
    // Update your webhooks key here
    $webhookKey = 'myWebhookKey';

    // Compute the payload with HMACSHA256 with base64 encoding
    $computedSignatureKey = base64_encode(
        hash_hmac('sha256', $rawPayload, $webhookKey, true)
    );

    // Signature key from Xero request
    $xeroSignatureKey = $_SERVER['HTTP_X_XERO_SIGNATURE'];

    $isEqual = false;

    if (hash_equals($computedSignatureKey, $xeroSignatureKey)) {
        $isEqual = true;
        http_response_code(200);
        
        // getting and passing the data to the api functionality
        $data = json_decode($rawPayload);
        xero_api($data);
    } else {
        http_response_code(401);
    }
    ///////////////////////////////////////////////////////////////////////////
    // WEBHOOK AUTHENTICATION - END
    ///////////////////////////////////////////////////////////////////////////
?>

API代码:

<?php
///////////////////////////////////////////////////////////////////////////
// XERO API FUNCITONALITY - START
///////////////////////////////////////////////////////////////////////////
function xero_api($data) {
    if ($data->events[0]->eventType === 'CREATE') {
        $resourseId = $data->events[0]->resourceId;

        ///////////////////////////////////////////////////////////////////////////
        // GET XERO CREDENTIALS - START
        ///////////////////////////////////////////////////////////////////////////
        global $wpdb;

        $xeroKeys = $wpdb->get_row("SELECT * FROM {$wpdb->prefix}xero_keys WHERE ID = 0", ARRAY_A);

        $clientId = $xeroKeys['client_id'];
        $clientSecret = $xeroKeys['client_secret'];
        $refreshToken = $xeroKeys['refresh_token'];
        $tenantId = $xeroKeys['tenant_id'];
        ///////////////////////////////////////////////////////////////////////////
        // GET XERO CREDENTIALS - END
        ///////////////////////////////////////////////////////////////////////////

        ///////////////////////////////////////////////////////////////////////////
        // GET ACCESS TOKEN AND GENERATE NEW REFRESH TOKEN - START
        ///////////////////////////////////////////////////////////////////////////
        $args = array(
            'headers' => array(
                'grant_type' => 'refresh_token',
            ),
            'body' => array(
                'grant_type' => 'refresh_token',
                'refresh_token' => $refreshToken,
                'client_id' => $clientId,
                'client_secret' => $clientSecret
            )
        );

        $refreshTokenRes = wp_remote_post('https://identity.xero.com/connect/token?=', $args);
        $refreshTokenBody = json_decode($refreshTokenRes['body']);

        if (isset($refreshTokenBody->refresh_token) && isset($refreshTokenBody->access_token)) {
            $updateTokens = $wpdb->update(
                $wpdb->prefix . 'xero_keys',
                array(
                    'refresh_token' => $refreshTokenBody->refresh_token,
                    'access_token' => $refreshTokenBody->access_token
                ),
                array('ID' => 0),
                array('%s', '%s'),
                array('%d')
            );
        }
        ///////////////////////////////////////////////////////////////////////////
        // GET ACCESS TOKEN AND GENERATE NEW REFRESH TOKEN - End
        ///////////////////////////////////////////////////////////////////////////

        $args = array(
            'headers' => array(
                'xero-tenant-id' => $tenantId,
                'Authorization' => 'Bearer ' . $refreshTokenBody->access_token,
                'Accept' => 'application/json',
                'Content-Type' => 'application/json'
            ),
        ); 

        $response = wp_remote_post('https://api.xero.com/api.xro/2.0/Invoices/' . $resourseId . '/Email', $args);
    }
}
///////////////////////////////////////////////////////////////////////////
// XERO API FUNCITONALITY - END
///////////////////////////////////////////////////////////////////////////
?>
9jyewag0

9jyewag01#

问题是你需要把这些电话分开。
正如对你的问题的评论所说,你需要首先处理webhook,然后排队将触发你的API的作业。像这样的东西

<?php
    ///////////////////////////////////////////////////////////////////////////
    // WEBHOOK AUTHENTICATION - START
    ///////////////////////////////////////////////////////////////////////////
    //hook section
    $rawPayload = file_get_contents("php://input");
    // Update your webhooks key here
    $webhookKey = 'myWebhookKey';

    // Compute the payload with HMACSHA256 with base64 encoding
    $computedSignatureKey = base64_encode(
        hash_hmac('sha256', $rawPayload, $webhookKey, true)
    );

    // Signature key from Xero request
    $xeroSignatureKey = $_SERVER['HTTP_X_XERO_SIGNATURE'];

    $isEqual = false;

    if (hash_equals($computedSignatureKey, $xeroSignatureKey)) {
        $isEqual = true;
        http_response_code(200);
        
        // getting and passing the data to the api functionality
        $data = json_decode($rawPayload);

        wp_schedule_single_event(
            time() + 10,
            'send_xero_api_call',
            ['data' => $data]
        );
    } else {
        http_response_code(401);
    }
    ///////////////////////////////////////////////////////////////////////////
    // WEBHOOK AUTHENTICATION - END
    ///////////////////////////////////////////////////////////////////////////

然后你需要注册一个WP Cron

add_action('send_xero_api_call', 'xero_api_cron', 10);

function xero_api_cron($data) {
    if ($data->events[0]->eventType === 'CREATE') {
        $resourseId = $data->events[0]->resourceId;

        ///////////////////////////////////////////////////////////////////////////
        // GET XERO CREDENTIALS - START
        ///////////////////////////////////////////////////////////////////////////
        global $wpdb;

        $xeroKeys = $wpdb->get_row("SELECT * FROM {$wpdb->prefix}xero_keys WHERE ID = 0", ARRAY_A);

        $clientId = $xeroKeys['client_id'];
        $clientSecret = $xeroKeys['client_secret'];
        $refreshToken = $xeroKeys['refresh_token'];
        $tenantId = $xeroKeys['tenant_id'];
        ///////////////////////////////////////////////////////////////////////////
        // GET XERO CREDENTIALS - END
        ///////////////////////////////////////////////////////////////////////////

        ///////////////////////////////////////////////////////////////////////////
        // GET ACCESS TOKEN AND GENERATE NEW REFRESH TOKEN - START
        ///////////////////////////////////////////////////////////////////////////
        $args = array(
            'headers' => array(
                'grant_type' => 'refresh_token',
            ),
            'body' => array(
                'grant_type' => 'refresh_token',
                'refresh_token' => $refreshToken,
                'client_id' => $clientId,
                'client_secret' => $clientSecret
            )
        );

        $refreshTokenRes = wp_remote_post('https://identity.xero.com/connect/token?=', $args);
        $refreshTokenBody = json_decode($refreshTokenRes['body']);

        if (isset($refreshTokenBody->refresh_token) && isset($refreshTokenBody->access_token)) {
            $updateTokens = $wpdb->update(
                $wpdb->prefix . 'xero_keys',
                array(
                    'refresh_token' => $refreshTokenBody->refresh_token,
                    'access_token' => $refreshTokenBody->access_token
                ),
                array('ID' => 0),
                array('%s', '%s'),
                array('%d')
            );
        }
        ///////////////////////////////////////////////////////////////////////////
        // GET ACCESS TOKEN AND GENERATE NEW REFRESH TOKEN - End
        ///////////////////////////////////////////////////////////////////////////

        $args = array(
            'headers' => array(
                'xero-tenant-id' => $tenantId,
                'Authorization' => 'Bearer ' . $refreshTokenBody->access_token,
                'Accept' => 'application/json',
                'Content-Type' => 'application/json'
            ),
        ); 

        $response = wp_remote_post('https://api.xero.com/api.xro/2.0/Invoices/' . $resourseId . '/Email', $args);
    }
}

到这种程度的东西。$data参数应该包含你传递的数据(不是100%确定它是如何为你服务的)。此外,您还需要检查API的节流情况,以便调整作业的执行时间。并确保您有地方存储,如果您的后台作业成功完成。
我的一个建议是,既然你在数据库中存储敏感信息(访问和刷新令牌),那就在数据库中存储它们时加密它们,在获取它们时解密。
你可以检查我是如何在我的插件实现后台作业
https://github.com/dingo-d/woo-solo-api/blob/develop/src/Request/SoloApiRequest.php#L428-L438
您可以使用deliciousbrains中的WP队列库:https://github.com/deliciousbrains/wp-queue/
它是WP Cron的 Package 器,带有用于处理队列的自定义DB表,这将允许您检查作业是否正确执行。

相关问题