欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

苹果应用内支付之服务端的实现

程序员文章站 2022-03-10 09:17:06
...

本文主要讲移动APP实现苹果支付的服务端实现步骤。

 

苹果应用内支付的流程可参考:

1、 官网说明:https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html#//apple_ref/doc/uid/TP40010573-CH104-SW1

 

2、中文博客:https://mengkang.net/723.html

 

简要说明如下:

1、首先客户端先请求苹果支付中心,支付中心返回给客户端一堆加密的数据。

2、然后客户端把这段加密的数据传给服务端。

3、最后由服务端端再去请求苹果支付中心来验证这次购买是否成功。如果验证通过,服务器端对业务逻辑进行处理。

 

本例实现方式:

客户端和服务端之间采用的websocket + JSON格式数据的通信方式。

服务端业务逻辑部分采用是Perl语言编写。

 

1、接口参数

{

"order_id":订单号(前端生成,32个字符内,保证唯一性)

"receipt_data":"MIITuwYJKoZIhvcNAQcCoIITrDCCE6g..."支付中心返回给客户端的加密数据

}

 

2、服务端请求支付中心验证票据

sub apple_check_receipt {

    my $receipt_data = $_[0];

 

    my $endpoint_debug = "https://sandbox.itunes.apple.com/verifyReceipt";  #开发环境,采用苹果沙盒地址

    if(__PACKAGE__ eq "PRODUCT") {

        $endpoint_debug = "https://buy.itunes.apple.com/verifyReceipt"; #生产环境

    }

    # 构造请求的参数(json格式)

    my $apple_receipt;

    $apple_receipt->{"receipt-data"} = $receipt_data;

 

    my $header = HTTP::Headers->new( Content_Type => 'application/json; charset=utf8', );

    my $json = JSON->new();

    my $http_request = HTTP::Request->new( POST => $endpoint_debug, $header, $json->encode($apple_receipt));

 

    #anlyse this response

    my $ua = LWP::UserAgent->new(ssl_opts => { verify_hostname => 0, SSL_verify_mode => 0x00 });

    $ua->timeout(30); 

    my $response = $ua->request($http_request);

    my $json_return;

    if ($response->message ne "OK" && $response->is_success ne "1") { #出错,或者timeout了

        return "timeout";

    } else {

        $json_return =  $json->decode($response->content());

    }

    # 验证苹果中心返回的结果

    if ($json_return->{status} eq "0") {

        my $in_app = $json_return->{receipt}->{in_app}[0];

        $result->{transaction_id} = $in_app->{transaction_id};

        if (length($result->{transaction_id}) == 0) {

            return "transaction_id is null";

        } elsif (length($in_app->{product_id}) == 0 || index($in_app->{product_id}, "abc.cdf.x") < 0) {

            return "product_id is invalid";

        }

         # 根据业务需求,验证其他字段

        .....

    }

    return "success";

}

 

验证票据请求返回结果的内容一般如下:

response: {

       environment: "Production", 

        receipt: {

            adam_id: 1155833660, 

            app_item_id: 1155833660, 

            application_version: "1", 

            bundle_id: "**********", 

            download_id: null, 

            in_app: [

                {

                    is_trial_period: "false", 

                    original_purchase_date: "2017-02-21 06:25:12 Etc/GMT", 

                    original_purchase_date_ms: "1487658312000", 

                    original_purchase_date_pst: "2017-02-20 22:25:12 America/Los_Angeles", 

                    original_transaction_id: "710000191974963", 

                    product_id: "***********", 

                    purchase_date: "2017-02-21 06:25:12 Etc/GMT", 

                    purchase_date_ms: "1487658312000", 

                    purchase_date_pst: "2017-02-20 22:25:12 America/Los_Angeles", 

                    quantity: "1", 

                    transaction_id: "710000191974963"

                }

            ], 

            original_application_version: "1", 

            original_purchase_date: "2017-02-21 06:25:12 Etc/GMT", 

            original_purchase_date_ms: "1487658312000", 

            original_purchase_date_pst: "2017-02-20 22:25:12 America/Los_Angeles", 

            receipt_creation_date: "2017-02-21 06:25:12 Etc/GMT", 

            receipt_creation_date_ms: "1487658312000", 

            receipt_creation_date_pst: "2017-02-20 22:25:12 America/Los_Angeles", 

            receipt_type: "Production", 

            request_date: "2017-02-21 06:25:22 Etc/GMT", 

            request_date_ms: "1487658312010", 

            request_date_pst: "2017-02-20 22:25:22 America/Los_Angeles", 

            version_external_identifier: 820590861

        }, 

        status: "0"

 

    },

每个字段的含义可以参考官网说明:https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html#//apple_ref/doc/uid/TP40010573-CH106-SW1

 

关键信息是在 in_app这个数组里面,可以根据自身情况,校验相应字段的合法性。

 

生产环境中还经常出现in_app为空数组的情况,比如下面的结果:

response: {

        environment: "Production", 

        receipt: {

            adam_id: 1155833660, 

            app_item_id: 1155833660, 

            application_version: "1", 

            bundle_id: "***********", 

            download_id: 83024344988508, 

            in_app: [ ], 

            original_application_version: "1", 

            original_purchase_date: "2017-03-26 10:26:17 Etc/GMT", 

            original_purchase_date_ms: "1490523977000", 

            original_purchase_date_pst: "2017-03-26 03:26:17 America/Los_Angeles", 

            receipt_creation_date: "2017-03-26 10:26:17 Etc/GMT", 

            receipt_creation_date_ms: "1490523977000", 

            receipt_creation_date_pst: "2017-03-26 03:26:17 America/Los_Angeles", 

            receipt_type: "Production", 

            request_date: "2017-03-26 10:26:27 Etc/GMT", 

            request_date_ms: "1490523977010", 

            request_date_pst: "2017-03-26 03:26:27 America/Los_Angeles", 

            version_external_identifier: 821061739

        }, 

        status: "0"

    },

 

这种都是不正常的。

 

另外客户端输入参数里面有order_id(保证唯一性)可以用来防止同一个票据数据receipt_data,重复发送导致服务端重复执行业务逻辑的问题。

 

 

 

 

 

 

相关标签: json apple perl