I want to build a payment page with the use of a payment page provider. I therefore created a class which builds with a futureBuilder the needed Widgets. From an API I want to receive an URL which I want to embed with an iFrame. However, the future data is every time null
and the snapshot has an error. But unfortunately this error is empty. From FlutterDevTools Network I could see that the http request remains pending. In Python I tried to do this request and it worked there (at the end I posted the relevant code of my script)
I struggle with two things. 1) I didn't find information how to solve the problem when the error remains empty and 2) why does the http request keep pending?
I tried e.g.
try {
response = await http.post(uriUrl, headers: headers, body: body);
} catch (e) {
print(e.toString());
}
But the error is empty. So it didn't help either.
[UPDATE 21.10.21]: I reached back to the people from the API and they see an incoming request, but my side (client) is cancelling before the server is able to respond.
What I've found is that 499 is a CLIENT CLOSED REQUEST which is a non-standard status code introduced by nginx for the case when a client closes the connection while nginx is processing the request.
I've found Possible reason for NGINX 499 error codes and people are suggesting increasing the timeout, but honestly I am overwhelmed as I am inexperienced with more elaborate http questions.
class _PaymentState extends State<Payment> {
late Future<PaymentPage> paymentPage;
@override
void initState() {
paymentPage =
APIManagerSaferpay().getPaymentPage(widget.price, widget.description);
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<PaymentPage>(
future: paymentPage,
builder: (context, snapshot) {
if (snapshot.hasError) {
// the code ends up here
return Center(child: Text(snapshot.error.toString()));
}
switch (snapshot.connectionState) {
case ConnectionState.none:
break;
case ConnectionState.active:
return const Center(child: CircularProgressIndicator());
case ConnectionState.done:
//debugger();
String url = snapshot.data!.redirectUrl;
return Center(
child: WebView(
initialUrl: Uri.dataFromString(
'<html><body><iframe src="$url"></iframe></body></html>',
mimeType: 'text/html')
.toString(),
javascriptMode: JavascriptMode.unrestricted,
));
This is how I wrote the async function getPaymentPage
that is invoked by the initState()
method.
class APIManagerSaferpay {
final String customerId = '******';
final String terminalId = '********';
String url = 'https://test.saferpay.com';
final String authHeader = 'API_******_********:JsonApiPwd1_************';
Future<PaymentPage> getPaymentPage(double total, String description) async {
url = 'https://test.saferpay.com/api/Payment/v1/PaymentPage/Initialize';
var bytes = utf8.encode(authHeader);
var base64StrCred = base64.encode(bytes);
var page = null;
final queryParameters = {
"RequestHeader": {
"SpecVersion": "1.24",
"CustomerId": "******",
"RequestId": "1234567890",
"RetryIndicator": 0
},
"TerminalId": "********",
"PaymentMethods": ["Twint"],
"Payment": {
"Amount": {"Value": "$total", "CurrencyCode": "CHF"},
"OrderId": "1234",
"Description": "Lunchroom"
},
"ReturnUrls": {
"Success": "https://amazon.com", // atm just arbitrary pages
"Fail": "https://youtube.com"
}
};
final body = jsonEncode(queryParameters);
final uriUrl = Uri.parse(url);
final headers = {
'Authorization': 'Basic $base64StrCred',
'Content-Type': 'application/json; charset=utf-8',
'Accept': 'application/json'
};
var response = null;
response = await http.post(uriUrl, headers: headers, body: body);
if (response.statusCode == 200) {
// this code is never reached
var jsonString = response.body;
var decoded = utf8.decode(jsonString.runes.toList());
page = PaymentPageFromJson(decoded);
}
if (response.statusCode >= 400) {
// this code is never reached
}
return page;
}
}
Screenshots from FlutterDevTools:
The request remains empty even though I defined the request header:
Screenshot shows that the request remains pending after the code broke (// the code ends up here
)
Functioning Python Code
import base64
...
authHeader = f'{username}:{pw}'
encodedCredentials = base64.b64encode(authHeader.encode()).decode()
header = {"Authorization": f"Basic {encodedCredentials}", "Content-Type": "application/json; charset=utf-8", "accept": "application/json"}
queryParameters = {
"RequestHeader": {
"SpecVersion": "1.24",
"CustomerId": ******,
"RequestId": "ccfbac3a8ef5151ae98035f45a609741",
"RetryIndicator": 0
},
"TerminalId": ********,
"PaymentMethods": ["TWINT"],
"Payment": {
"Amount": {"Value": "200", "CurrencyCode": "CHF"},
"OrderId": "2",
"Description": 'Lunchroom:'
},
"ReturnUrls": {
"Success": 'https://amazon.com',
"Fail": 'https://youtube.com'
}
}
response = requests.post(url="https://test.saferpay.com/api/Payment/v1/PaymentPage/Initialize", headers=header, json=queryParameters)