Много информации внутри!
Я знаю, что в этой проблеме много разных тем, но ответы на них не отвечают должным образом, а собственные уроки и ссылки Stripe намного лучше. так что, надеюсь, я (и другие) может окончательно увидеть свет в этой долговечной проблеме для нас, разработчиков хобби.
Я пытаюсь реализовать API-интерфейс Stripe уже более 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 и первым ECHO в PHP-скрипте, поскольку я никогда ничего не получаю, кроме огромного сообщения 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: <com.stripe.android.model.Token@... id=> JSON: { from API request 'req_...' 08-23 16:04:28.083 20867-20867/... E/DatabaseTask: "card": { 08-23 16:04:28.083 20867-20867/... E/DatabaseTask: "address_city": null, 08-23 16:04:28.083 20867-20867/... E/DatabaseTask: "address_country": null, 08-23 16:04:28.083 20867-20867/... E/DatabaseTask: "address_line1": null, 08-23 16:04:28.083 20867-20867/... E/DatabaseTask: "address_line2": null, 08-23 16:04:28.083 20867-20867/... E/DatabaseTask: "address_state": null, 08-23 16:04:28.083 20867-20867/... E/DatabaseTask: "address_zip": null, 08-23 16:04:28.083 20867-20867/... E/DatabaseTask: "country": "US", 08-23 16:04:28.083 20867-20867/... E/DatabaseTask: "currency": null, 08-23 16:04:28.083 20867-20867/... E/DatabaseTask: "cvc": null, 08-23 16:04:28.083 20867-20867/... E/DatabaseTask: "exp_month": 12, 08-23 16:04:28.083 20867-20867/... E/DatabaseTask: "exp_year": 2019, 08-23 16:04:28.083 20867-20867/... E/DatabaseTask: "fingerprint": null, 08-23 16:04:28.083 20867-20867/... E/DatabaseTask: "last4": "4242", 08-23 16:04:28.083 20867-20867/... E/DatabaseTask: "name": null, 08-23 16:04:28.083 20867-20867/... E/DatabaseTask: "number": null, 08-23 16:04:28.083 20867-20867/... E/DatabaseTask: "type": null 08-23 16:04:28.083 20867-20867/... E/DatabaseTask: }, 08-23 16:04:28.083 20867-20867/... E/DatabaseTask: "created": "Aug 23, 2016 16:04:25", 08-23 16:04:28.083 20867-20867/... E/DatabaseTask: "id": "tok_...", 08-23 16:04:28.083 20867-20867/... E/DatabaseTask: "livemode": false, 08-23 16:04:28.083 20867-20867/... E/DatabaseTask: "used": 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->handleApiError('{\n "error": {\n...', 400, Array, Array) 08-23 16:04:28.083 20867-20867/... E/DatabaseTask: #1 /home/.../Stripe/lib/ApiRequestor.php(65): Stripe\ApiRequestor->_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: <com.stripe.android.model.Token@... id=> JSON: { from API request 'req_...' "card": { "address_city": null, "address_country": null, "address_line1": null, "address_line2": null, "address_state": null, "address_zip": null, "country": "US", "currency": null, "cvc": null, "exp_month": 12, "exp_year": 2019, "fingerprint": null, "last4": "4242", "name": null, "number": null, "type": null }, "created": "Aug 23, 2016 16:04:25", "id": "tok_...", "livemode": false, "used": false}' in /home/.../Stripe/lib/ApiRequestor.php:108Stack trace:#0 /home/.../Stripe/lib/ApiRequestor.php(227): Stripe\ApiRequestor->handleApiError('{\n "error": {\n...', 400, Array, Array)#1 /home/.../Stripe/lib/ApiRequestor.php(65): Stripe\ApiRequestor->_interpretRe in <b>/home/.../Stripe/lib/ApiRequestor.php</b> on line <b>108</b><br />
(ссылки, идентификаторы, токены и другие личные вещи заменяются …)
Поэтому я пробовал почти все, что мог найти в Интернете, о сообщении «Нет такого токена:», но безрезультатно.
Что я проверял: – Оба моих ключа в порядке, без промаха здесь. – Есть правильная связь между моим приложением и моим скриптом PHP. Токен создан правильно и проверен Stripe. Мой сервер имеет платный сертификат SSL и сделал безопасный соединение с HttpsURLConnection
Что я пробовал: – обновил ключи снова и снова – отправил мой токен в виде строки в методе POST – попытался отправить мой токен в виде JSONtoken (никогда не работал)> Передача маркеров Stripe на сервер и обработка на сервере – взял метод POST вне asyncTask (читал, что он не нужен) – снова и снова перечитывать всю документацию 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 года я собрал все свои знания по следам и ошибкам, и хотя я знаю некоторые вещи, я мог бы пропустить некоторые базовые знания.
Благодарю.
Ошибка здесь заключается в том, что вместо передачи идентификатора tok_XXX
вы передаете весь объект Token, который вы вернули из SDK Stripe. После этого запрос не выполняется с ошибкой
Необязательное исключение «Stripe \ Error \ InvalidRequest» с сообщением «Нет такого токена: <com.stripe.android.model.Token @ … id => JSON: {из запроса API 'req _…'
Вам нужно изменить свой код для отправки идентификатора токена вместо вашего PHP-скрипта, который должен устранить проблему.
builder.append(URLEncoder.encode(token.getId(), "UTF-8"));