首页 > 解决方案 > Swift 中的 HTTP Post 到 PHP 给出 code=3840

问题描述

我正在尝试向我的服务器发送一个应用程序收据字符串,该服务器反过来查询 Apple 的 verifyReceipt 端点,但是我收到以下错误:

Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.}

如果我将收据字符串硬编码到我的 PHP 中,我会收到正确的 JSON 输出,如下所示:

string(2759) "{ "receipt":{"receipt_type":"ProductionSandbox", "adam_id":0, "app_item_id":0, "bundle_id":"com.Test.SQLExplorer", "application_version":"1", "download_id":0, "version_external_identifier":0, "receipt_creation_date":"2020-05-06 15:24:21 Etc/GMT", "receipt_creation_date_ms":"1588778661000", "receipt_creation_date_pst":"2020-05-06 08:24:21 America/Los_Angeles", "request_date":"2020-05-06 15:55:01 Etc/GMT", "request_date_ms":"1588780501918", "request_date_pst":"2020-05-06 08:55:01 America/Los_Angeles", "original_purchase_date":"2013-08-01 07:00:00 Etc/GMT", "original_purchase_date_ms":"1375340400000", "original_purchase_date_pst":"2013-08-01 00:00:00 America/Los_Angeles", "original_application_version":"1.0", "in_app":[ {"quantity":"1", "product_id":"com.Test.SQLExplorer.extrasubject", "transaction_id":"1000000659868895", "original_transaction_id":"1000000659868895", "purchase_date":"2020-05-04 10:55:57 Etc/GMT", "purchase_date_ms":"1588589757000", "purchase_date_pst":"2020-05-04 03:55:57 America/Los_Angeles", "original_purchase_date":"2020-05-04 10:55:57 Etc/GMT", "original_purchase_date_ms":"1588589757000", "original_purchase_date_pst":"2020-05-04 03:55:57 America/Los_Angeles", "is_trial_period":"false"}, {"quantity":"1", "product_id":"com.Test.SQLExplorer.IAP2", "transaction_id":"1000000659963594", "original_transaction_id":"1000000659963594", "purchase_date":"2020-05-04 14:27:40 Etc/GMT", "purchase_date_ms":"1588602460000", "purchase_date_pst":"2020-05-04 07:27:40 America/Los_Angeles", "original_purchase_date":"2020-05-04 14:27:40 Etc/GMT", "original_purchase_date_ms":"1588602460000", "original_purchase_date_pst":"2020-05-04 07:27:40 America/Los_Angeles", "is_trial_period":"false"}, {"quantity":"1", "product_id":"com.Test.SQLExplorer.IAP3", "transaction_id":"1000000660362367", "original_transaction_id":"1000000660362367", "purchase_date":"2020-05-05 12:55:01 Etc/GMT", "purchase_date_ms":"1588683301000", "purchase_date_pst":"2020-05-05 05:55:01 America/Los_Angeles", "original_purchase_date":"2020-05-05 12:55:01 Etc/GMT", "original_purchase_date_ms":"1588683301000", "original_purchase_date_pst":"2020-05-05 05:55:01 America/Los_Angeles", "is_trial_period":"false"}, {"quantity":"1", "product_id":"com.Test.SQLExplorer.IAP1", "transaction_id":"1000000659963406", "original_transaction_id":"1000000659963406", "purchase_date":"2020-05-04 14:26:57 Etc/GMT", "purchase_date_ms":"1588602417000", "purchase_date_pst":"2020-05-04 07:26:57 America/Los_Angeles", "original_purchase_date":"2020-05-04 14:26:57 Etc/GMT", "original_purchase_date_ms":"1588602417000", "original_purchase_date_pst":"2020-05-04 07:26:57 America/Los_Angeles", "is_trial_period":"false"}]}, "status":0, "environment":"Sandbox"}"

但是,当我在以下 HTTP POST 请求中使用它时,它会因错误而失败,这表明问题出在其中。有什么想法我哪里出错了吗?

邮政

func sendReceipt(receiptString: String) {
        let basePath = "https://www.example.com/validate.php"
        let pathAsURL: URL = URL(string: basePath)!
        let parameterDictionary = ["encodedReceipt" : receiptString]
        
        var request = URLRequest(url: pathAsURL)
        request.httpMethod = "POST"
        request.setValue("Application/json", forHTTPHeaderField: "Content-Type")
        guard let httpBody = try? JSONSerialization.data(withJSONObject: parameterDictionary, options: []) else { return }
        request.httpBody = httpBody

        let session = URLSession.shared
        session.dataTask(with: request) { (data, response, error) in
            if let response = response {
                print(response)
            }
            
            if let data = data {
                do {
                    let json = try JSONSerialization.jsonObject(with: data, options: [])
                    print(json)
                }catch {
                    print(error)
                }
            }
            }
        .resume()
    }

PHP

<?php
  
//Read input from POST request
$inputreceipt = json_decode(file_get_contents('php://input'), true);
    
//Get receiptstring from json input
$receipt_data = $inputreceipt['encodedReceipt'];
    
//JSON bundle to be sent to app store
$data = json_encode(["receipt-data" => $receipt_data]);
    
//$url = "https://buy.itunes.apple.com/verifyReceipt";    //production
$url = "https://sandbox.itunes.apple.com/verifyReceipt";  //sandbox

echo post($url,$data);

function post($url, $data, $headerArray = array())
{
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST,FALSE);
    curl_setopt($curl, CURLOPT_POST, 1);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    if (array() === $headerArray)
        curl_setopt($curl, CURLOPT_HTTPHEADER,["Content-type:application/json;charset='utf-8'","Accept:application/json"]);

    $output = curl_exec($curl);
    curl_close($curl);
    return $output;
}
?>

标签: phpiosswift

解决方案


我最终解决了几个问题:

1)在sendReceipt方法 let parameterDictionary = ["encodedReceipt" : "\(receiptString)"]更改为let parameterDictionary = ["encodedReceipt" : receiptString]

2) 在 PHP var_dump(post($url,$data));中为返回的 JSON 添加了很多额外的东西。改为压制echo post($url,$data);

如果有人感兴趣,原始帖子已更新为正确的工作代码。


推荐阅读