`
lzqustc
  • 浏览: 206629 次
  • 性别: Icon_minigender_1
  • 来自: 厦门
社区版块
存档分类
最新评论

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

    博客分类:
  • Perl
阅读更多

本文主要讲移动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,重复发送导致服务端重复执行业务逻辑的问题。

 

 

 

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics