用Android发送条带令牌的正确方式


the correct way of sending a stripe token with Android

里面有很多信息!

我知道有很多关于这个问题的线程,但是没有一个是正确的回答,Stripe自己的教程和参考也没有更好。所以希望我(和其他人)能够最终为我们这些业余开发者看到这个长期存在的问题。

我一直试图实现条纹的API超过2周现在,仍然停留在同样的问题。我的Android代码正常工作,直到我从Stripe收到我的Token。

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);
    }

这个DB任务的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之间的某个地方出错了,因为我从来没有得到任何回报,除了在我的控制台中出现一个巨大的错误消息。

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,令牌和其他个人物品被替换为…)

所以我已经尝试了几乎所有我能在网上找到的关于"No such Token:"的消息,但无济于事。

我检查了什么:-我的两把钥匙都没问题,没有错-我的应用程序和我的PHP脚本之间有一个适当的连接—token创建正确,并经过Stripe验证-我的服务器有一个付费的SSL证书,并与HttpsURLConnection建立了一个安全连接

我试过什么?-一遍又一遍地刷新按键-发送我的令牌作为一个字符串在POST方法-尝试将我的令牌作为JSONtoken发送(从未让它工作)>将条纹令牌传递到服务器并在服务器上处理-在asyncTask之外获取POST方法(读到它不需要)-重新阅读条纹的整个文档一遍又一遍> https://stripe.com/docs/mobile/android-一遍又一遍地分割示例项目> https://github.com/stripe/stripe-android/tree/master/example-搜索视频教程,但只在网站上找到整合教程-搜索在线课程,同样只搜索web集成

所以现在我真的想知道这个看似不可能完成的任务是什么意思:

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

如果你需要更多的信息,请不要犹豫,因为这是完成我的第一个适当的申请的最后一步。另外,请记住,我在过去的3年里积累了所有的知识,虽然我知道很多东西,但我可能会错过一些基本的知识。

谢谢。

这里的错误是,不是传递令牌id tok_XXX,而是传递整个令牌对象,您从Stripe的SDK返回。然后请求失败,并报错

未捕获的异常'Stripe'Error'InvalidRequest'伴有消息'No such token: <com.stripe.android.model.Token@..。id>

你需要改变你的代码发送令牌id,而不是你的PHP脚本应该解决这个问题。

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