【问题标题】:the correct way of sending a stripe token with Android使用 Android 发送条带令牌的正确方法
【发布时间】:2016-12-30 10:53:36
【问题描述】:

里面有很多信息!

我知道关于这个问题有多个线程,但没有一个得到正确回答,而且 Stripe 自己的教程和参考资料也好不到哪里去。因此,希望我(和其他人)最终能够为我们的业余开发者看到这个长期存在的问题。

我已经尝试实现 Stripe 的 API 超过 2 周了,但仍然遇到同样的问题。我的 Android 代码正常运行,直到我从 Stripe 收到我的令牌。

public class Checkout extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_checkout);
    }

    public void submitCard(View view) throws AuthenticationException {


        TextView cardNumberField = (TextView) findViewById(R.id.cardNumber);
        TextView monthField = (TextView) findViewById(R.id.month);
        TextView yearField = (TextView) findViewById(R.id.year);
        TextView cvcField = (TextView) findViewById(R.id.cvc);

        Card card = new Card(cardNumberField.getText().toString(), Integer.valueOf(monthField.getText().toString()), Integer.valueOf(yearField.getText().toString()), cvcField.getText().toString());
        //Card newCard = new Card("4242 4242 4242 4242", 12, 19, "123");

        Stripe stripe = new Stripe("pk_test_key");
        stripe.createToken(card, new TokenCallback() {
            @Override
            public void onError(Exception error) {
                //Error
                Toast.makeText(getApplicationContext(), error.getLocalizedMessage(), Toast.LENGTH_LONG).show();
            }

            @Override
            public void onSuccess(Token token) {
                //send token to server
                Toast.makeText(getApplicationContext(), "Succesfully created a token", Toast.LENGTH_LONG).show();       // < this toast works, so my token is fine

                DatabaseTask databaseTask = new DatabaseTask("SENDTOKEN", token);
                databaseTask.execute();

            }
        });
    }

}

创建令牌后,我启动我的 DatabaseTask,然后它应该将该令牌发送到我的服务器(货币和金额在 PHP 脚本 atm 中硬编码)。这个服务器有一个付费的 SSL 证书,我正在创建一个到我的 PHP 脚本的安全连接,它应该处理其余的。

public class DatabaseTask extends AsyncTask<String, Void, String> {

    String command = "";
    Token token;

    public DatabaseTask(String mCommand, Token mToken){
        command = mCommand;
        token = mToken;
    }

    @Override
    protected String doInBackground(String... strings) {

        String echoData = "";

        if (command.equals("SENDTOKEN")) {
            try {
                URL url = new URL("https://.../StripeConnection.php"); //there is a connection between the code and PHP script. This is tested.
                HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();


                StringBuilder builder = new StringBuilder();
                builder.append(URLEncoder.encode("stripeToken", "UTF-8"));
                builder.append("=");
                builder.append(URLEncoder.encode(token.toString(), "UTF-8"));
                String urlParameters = builder.toString();

                connection.setRequestMethod("POST");
                connection.setDoOutput(true);
                DataOutputStream dStream = new DataOutputStream(connection.getOutputStream());

                dStream.writeBytes(urlParameters);
                dStream.flush();
                dStream.close();

                BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                String line = "";
                StringBuilder responseOutput = new StringBuilder();

                while ((line = br.readLine()) != null) {
                    Log.e("DatabaseTask", line);
                    responseOutput.append(line);
                }
                br.close();

                echoData = responseOutput.toString();


            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return echoData;
    }

    protected void onPostExecute(String mData){
        Log.e("DatabaseTask", "onPostExecute result: " + mData);
    }

这个数据库任务的 PHP 脚本:

<?php

require_once('Stripe/init.php');

\Stripe\Stripe::setApiKey("sk_test_key");

$token = $_POST['stripeToken'];
$price = $_POST['price'];
$description = $_POST['description'];

// Create the charge on Stripe's servers - this will charge the user's card
try {
  $charge = Stripe\Charge::create(array(
    "amount" => 10000,          //"amount" => $price, in cents. //Hardcoded for testing
    "currency" => "cny",                        //Hardcoded for testing
    "source" => $token,                         //Hardcoded for testing
    "description" => "omschrijving" //"description" => $description //Hardcoded for testing
    ));

    echo "payment went succesfull";
} catch(\Stripe\Error\Card $e) {
  // The card has been declined
  echo "card was declined";
}

?>

似乎在我执行 DatabaseTask 和 PHP 脚本中的第一个 ECHO 之间的某个地方出现了问题,因为除了控制台中出现巨大的 ERROR 消息外,我再也没有得到任何回复。

08-23 16:04:28.083 20867-20867/... E/DatabaseTask: <br />
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: <b>Fatal error</b>:  Uncaught exception 'Stripe\Error\InvalidRequest' with message 'No such token: &lt;com.stripe.android.model.Token@... id=&gt; JSON: { from API request 'req_...'
08-23 16:04:28.083 20867-20867/... E/DatabaseTask:   &quot;card&quot;: {
08-23 16:04:28.083 20867-20867/... E/DatabaseTask:     &quot;address_city&quot;: null,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask:     &quot;address_country&quot;: null,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask:     &quot;address_line1&quot;: null,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask:     &quot;address_line2&quot;: null,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask:     &quot;address_state&quot;: null,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask:     &quot;address_zip&quot;: null,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask:     &quot;country&quot;: &quot;US&quot;,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask:     &quot;currency&quot;: null,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask:     &quot;cvc&quot;: null,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask:     &quot;exp_month&quot;: 12,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask:     &quot;exp_year&quot;: 2019,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask:     &quot;fingerprint&quot;: null,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask:     &quot;last4&quot;: &quot;4242&quot;,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask:     &quot;name&quot;: null,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask:     &quot;number&quot;: null,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask:     &quot;type&quot;: null
08-23 16:04:28.083 20867-20867/... E/DatabaseTask:   },
08-23 16:04:28.083 20867-20867/... E/DatabaseTask:   &quot;created&quot;: &quot;Aug 23, 2016 16:04:25&quot;,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask:   &quot;id&quot;: &quot;tok_...&quot;,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask:   &quot;livemode&quot;: false,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask:   &quot;used&quot;: false
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: }' in /home/.../Stripe/lib/ApiRequestor.php:108
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: Stack trace:
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: #0 /home...Stripe/lib/ApiRequestor.php(227): Stripe\ApiRequestor-&gt;handleApiError('{\n  &quot;error&quot;: {\n...', 400, Array, Array)
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: #1 /home/.../Stripe/lib/ApiRequestor.php(65): Stripe\ApiRequestor-&gt;_interpretRe in <b>/home/.../Stripe/lib/ApiRequestor.php</b> on line <b>108</b><br />
08-23 16:04:28.093 20867-20867/... E/Checkout: <br /><b>Fatal error</b>:  Uncaught exception 'Stripe\Error\InvalidRequest' with message 'No such token: &lt;com.stripe.android.model.Token@... id=&gt; JSON: { from API request 'req_...'  &quot;card&quot;: {    &quot;address_city&quot;: null,    &quot;address_country&quot;: null,    &quot;address_line1&quot;: null,    &quot;address_line2&quot;: null,    &quot;address_state&quot;: null,    &quot;address_zip&quot;: null,    &quot;country&quot;: &quot;US&quot;,    &quot;currency&quot;: null,    &quot;cvc&quot;: null,    &quot;exp_month&quot;: 12,    &quot;exp_year&quot;: 2019,    &quot;fingerprint&quot;: null,    &quot;last4&quot;: &quot;4242&quot;,    &quot;name&quot;: null,    &quot;number&quot;: null,    &quot;type&quot;: null  },  &quot;created&quot;: &quot;Aug 23, 2016 16:04:25&quot;,  &quot;id&quot;: &quot;tok_...&quot;,  &quot;livemode&quot;: false,  &quot;used&quot;: false}' in /home/.../Stripe/lib/ApiRequestor.php:108Stack trace:#0 /home/.../Stripe/lib/ApiRequestor.php(227): Stripe\ApiRequestor-&gt;handleApiError('{\n  &quot;error&quot;: {\n...', 400, Array, Array)#1 /home/.../Stripe/lib/ApiRequestor.php(65): Stripe\ApiRequestor-&gt;_interpretRe in <b>/home/.../Stripe/lib/ApiRequestor.php</b> on line <b>108</b><br />

(链接、ID、令牌和其他个人资料被替换为...)

所以我已经尝试了几乎所有我可以在网上找到的关于“没有这样的令牌:”的消息,但无济于事。

我检查了什么: - 我的两个键都可以,这里没有不匹配 - 我的应用程序和我的 PHP 脚本之间有正确的连接 - 令牌已正确创建并由 Stripe 验证 - 我的服务器拥有付费 SSL 证书并与 HttpsURLConnection 建立了安全连接

我尝试了什么: - 一遍又一遍地刷新键 - 在 POST 方法中将我的令牌作为字符串发送 - 尝试将我的令牌作为 JSONtoken 发送(从未让它工作)> Passing Stripe tokens to server and handling on server - 在 asyncTask 之外使用 POST 方法(读到它不需要) - 一遍又一遍地重新阅读 Stripe 的整个文档 > https://stripe.com/docs/mobile/android - 一遍又一遍地检查示例项目 > https://github.com/stripe/stripe-android/tree/master/example - 搜索视频教程,但只找到网站上的集成教程 - 搜索在线课程,再次仅用于网络集成

所以现在我真的很想知道 Stripe 对这项几乎不可能完成的任务意味着什么:

在您的服务器上设置一个可以接收 HTTP POST 调用的端点 为令牌。在 onActivityResult 方法(适用于 Android Pay)或 onSuccess 回调(使用您自己的表单时),您需要发布 向您的服务器提供令牌。确保与您的任何沟通 服务器受 SSL 保护以防止窃听。

如果您需要更多信息,请不要犹豫,因为这是完成我的第一个正确申请的最后一步。另外,请记住,我在过去 3 年中通过反复试验收集了我所有的知识,即使我知道很多东西,我也可能会错过一些基本知识。

谢谢。

【问题讨论】:

    标签: php android token stripe-payments


    【解决方案1】:

    这里的错误是,您没有传递令牌 ID tok_XXX,而是传递了您从 Stripe 的 SDK 返回的整个 Token 对象。然后请求失败并出现错误

    未捕获的异常 'Stripe\Error\InvalidRequest' 带有消息'没有这样的令牌: JSON:{来自 API 请求 'req_...'

    您需要更改代码以将令牌 ID 发送到应该可以解决问题的 PHP 脚本。

    builder.append(URLEncoder.encode(token.getId(), "UTF-8"));
    

    【讨论】:

    • 天哪,你救了我的命!我不敢相信这很容易。这就是为什么我非常讨厌不完整的文档,除了那部分之外,它们都列出了所有内容。因此,如果我是正确的,我会收到一份仍然存在于 Stripe 的服务器上的令牌副本,并且要完成购买,我只需向他们发送令牌 ID,以便他们知道向谁收费?无论如何,再次感谢您的解决方案!作为回报,我能想到的只是在我的下一个视频博客中喊市长。那样你觉得可以吗?干杯!
    • 没错,你只需要发送id即可。如果需要,您始终可以使用检索令牌 API (stripe.com/docs/api#retrieve_token) 检索完整的对象服务器端!我总是很乐意提供帮助:)
    猜你喜欢
    • 2020-01-15
    • 1970-01-01
    • 2018-11-25
    • 2018-10-16
    • 2019-02-16
    • 2015-08-06
    • 2016-11-23
    • 2016-06-19
    • 2021-12-20
    相关资源
    最近更新 更多