Hy everybody,
I try now to get the precent of completion of a http get request, but this cann't work, every time I get this error:
flutter: Bad state: Can't finalize a finalized Request.
Code I writed:
http.Response response = await client.get(url, headers: {"email": email, "password": password});
var __ = await client.send(response.request);
var length = response.contentLength;
var received = 0;
__.stream.map((s) {
received += s.length;
print("${(received / length) * 100} %");
return 1;
});
finally I should get a json data.
Could have anyone a ideea, how can this fixed or other programmed?
use Dio package it includes up/download status counter
Related
I am trying to receive notifications in an Expo React Native App.
The notifications will be sent using Azure Notification Hub REST API
I followed the steps below :
Added the Android project in Firebase Console
To get the Server Key I followed - Firebase messaging, where to get Server Key?
Configured the FCM ServerKey in Azure Notification Hub
Added the google-services.json at the root in my React Native App and modified app.json as mentioned in - https://docs.expo.dev/push-notifications/using-fcm/
To register in ANH, we first need the SAS Token - https://learn.microsoft.com/en-us/rest/api/notificationhubs/common-concepts I generated the token with the following code
const Crypto = require('crypto-js');
const resourceURI =
'http://myNotifHubNameSpace.servicebus.windows.net/myNotifHubName ';
const sasKeyName = 'DefaultListenSharedAccessSignature';
const sasKeyValue = 'xxxxxxxxxxxx';
const expiresInMins = 200;
let sasToken;
let location;
let registrationID;
let deviceToken;
function getSASToken(targetUri, sharedKey, ruleId, expiresInMins) {
targetUri = encodeURIComponent(targetUri.toLowerCase()).toLowerCase();
// Set expiration in seconds
var expireOnDate = new Date();
expireOnDate.setMinutes(expireOnDate.getMinutes() + expiresInMins);
var expires =
Date.UTC(
expireOnDate.getUTCFullYear(),
expireOnDate.getUTCMonth(),
expireOnDate.getUTCDate(),
expireOnDate.getUTCHours(),
expireOnDate.getUTCMinutes(),
expireOnDate.getUTCSeconds()
) / 1000;
var tosign = targetUri + '\n' + expires;
// using CryptoJS
//var signature = CryptoJS.HmacSHA256(tosign, sharedKey);
var signature = Crypto.HmacSHA256(tosign, sharedKey);
var base64signature = signature.toString(Crypto.enc.Base64);
//var base64signature = signature.toString(CryptoJS.enc.Base64);
var base64UriEncoded = encodeURIComponent(base64signature);
// construct autorization string
var token =
'SharedAccessSignature sr=' +
targetUri +
'&sig=' +
base64UriEncoded +
'&se=' +
expires +
'&skn=' +
ruleId;
console.log('signature:' + token);
return token;
}
I then called the create registration API - https://learn.microsoft.com/en-us/rest/api/notificationhubs/create-registration-id
The registrationID has to be extracted from the response header of the API Call
I used the following code to generate the ANH Regsitration ID
async function createRegistrationId() {
const endpoint =
'https://xxxxxx.servicebus.windows.net/xxxxxxx/registrationIDs/?api-version=2015-01';
sasToken = getSASToken(resourceURI, sasKeyValue, sasKeyName, expiresInMins);
const headers = {
Authorization: sasToken,
};
const options = {
method: 'POST',
headers: headers,
};
const response = await fetch(endpoint, options);
if (response.status !== 201) {
console.log(
'Unbale to create registration ID. Status Code: ' + response.status
);
}
console.log('Response Object : ', response);
for (var pair of response.headers.entries()) {
//console.log(pair[0] + ': ' + pair[1]);
}
location = response.headers.get('Location');
console.log('Location - ' + location);
console.log('Type - ' + response.type);
registrationID = location.substring(
location.lastIndexOf('registrationIDs/') + 'registrationIDs/'.length,
location.lastIndexOf('?api-version=2015-01')
);
console.log('Regsitration ID - ', registrationID);
return location;
}
Next step was to update this registration ID in ANH with the Native Device Token
I used expo-notifications package and the method getDevicePushTokenAsync() method to get the native device token
async function registerForPushNotificationsAsync() {
let token;
if (Device.isDevice) {
const { status: existingStatus } = await Notifications.getPermissionsAsync();
let finalStatus = existingStatus;
if (existingStatus !== 'granted') {
const {
status
} = await Notifications.requestPermissionsAsync();
finalStatus = status;
}
if (finalStatus !== 'granted') {
alert('Failed to get push token for push notification!');
return;
}
token = (await Notifications.getDevicePushTokenAsync()).data;
console.log(token);
} else {
alert('Must use physical device for Push Notifications');
}
if (Platform.OS === 'android') {
Notifications.setNotificationChannelAsync('default', {
name: 'default',
importance: Notifications.AndroidImportance.MAX,
vibrationPattern: [0, 250, 250, 250],
lightColor: '#FF231F7C',
});
}
return token;
}
The native device token was in the following format on Android device
c6RI81R7Rn66kWZ0rar3M2:APA91bEcbLXGwEZF-8hu1yGHfXgWBNuxr_4NY_MR8d7HEzeHAJrjoJnjUlneAIiVglCNIGUr11qkP1G4S76bx_H7NItxfQhZa_bgnQjqSlSaY4-oCoarDYWcY-Mz_ulW8rQZFy_SA6_j
I then called the updateRegistrationId API - https://learn.microsoft.com/en-us/rest/api/notificationhubs/create-update-registration
async function updateRegistraitonId() {
//IF you use registrationIDs as in returned location it was giving 401 error
const endpoint =
'https://xxxxx.servicebus.windows.net/xxxxxxx/registrations/' +
registrationID +
'?api-version=2015-01';
const endpoint1 = location;
const headers = {
Authorization: sasToken,
'Content-Type': 'application/atom+xml;type=entry;charset=utf-8',
};
//Remember to create well-formed XML using back-ticks
//else you may get 400 error
//If you use the tags element it was giving an error
const regDATA = `<entry xmlns="http://www.w3.org/2005/Atom">
<content type="application/xml">
<GcmRegistrationDescription xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/netservices/2010/10/servicebus/connect">
<GcmRegistrationId>${deviceToken}</GcmRegistrationId>
</GcmRegistrationDescription>
</content>
</entry>`;
const options = {
method: 'PUT',
headers: headers,
body: regDATA,
};
const response = await fetch(endpoint, options);
if (response.status !== 201) {
console.log(
'Looks like there was a problem. Status Code: ' + response.status
);
console.log('Response Object : ', response);
//return;
}
}
According to API documentation, I should get 201 response, I got 200 response code . I am not sure if this is the issue
After this I had the notification handling code to recieve the notification,similar to the code in - https://docs.expo.dev/versions/latest/sdk/notifications/
I then tried to send notification using Test Send from ANH, it failed with the error -
**
"The Token obtained from the Token Provider is wrong"
**
I checked in ANH Metrics, the error was categorized as GCM Authentication error, GCM Result:Mismatch SenderId
I tried to check for documentation to add the SenderId , but I couldnt find anyway to inlcude the SenderId also in the payload of updateRegistration call (in xml atom entry)
I tried to use the device token and send directly from Firebase Console, I did not receive it either.
I used the Direct Send API of Azure notification Hub but still did not receive anything
I am suspecting there could be some issue in the way I am handling notifiations in the client device, I can fix that later , but first I will have to resolve the error I am getting in Test Send in Azure NH
Any help to be able to successfully send using Test Send in ANH or pointers ahead for next steps will be much appreciated
I am creating a post request Using Dio,
this is my FormData params,
FormData formData = FormData.fromMap({
'wallet_id': '${dropdownValue.walletId}',
'member_id': '${_loginModel.memberId}',
'draw_amount': withdrawalAmountContoller.text,
'login_password': passwordController.text,
});
then I am passing params like this,
Response response = await dio.post(url, data: params);
But I am getting an error on request,
ERROR[DioError [DioErrorType.RESPONSE]: Http status error [405]] => PATH: https://vertoindiapay.com/pay/api/withdraw
E/flutter ( 6703): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: DioError [DioErrorType.RESPONSE]: Http status error [405]
E/flutter ( 6703): #0 DioMixin._request._errorInterceptorWrapper. (package:dio/src/dio.dart:848:13)
Please help me solve this. My URL is=> https://vertoindiapay.com/pay/api/withdraw
Although this is working fine in postman,
Future<void> signUpUser() async {
final formData = {
'username': 'test1',
'password': 'abcdefg',
'grant_type': 'password',
};
try {
Dio _dio = new Dio();
_dio.options.contentType = Headers.formUrlEncodedContentType;
final responseData = await _dio.post<Map<String, dynamic>>('/token',
options: RequestOptions(
method: 'POST',
headers: <String, dynamic>{},
baseUrl: 'http://52.66.71.229/'),
data: formData);
print(responseData.toString());
} catch (e) {
final errorMessage = DioExceptions.fromDioError(e).toString();
print(errorMessage);
}
}
class DioExceptions implements Exception {
DioExceptions.fromDioError(DioError dioError) {
switch (dioError.type) {
case DioErrorType.CANCEL:
message = "Request to API server was cancelled";
break;
case DioErrorType.CONNECT_TIMEOUT:
message = "Connection timeout with API server";
break;
case DioErrorType.DEFAULT:
message = "Connection to API server failed due to internet connection";
break;
case DioErrorType.RECEIVE_TIMEOUT:
message = "Receive timeout in connection with API server";
break;
case DioErrorType.RESPONSE:
message =
_handleError(dioError.response.statusCode, dioError.response.data);
break;
case DioErrorType.SEND_TIMEOUT:
message = "Send timeout in connection with API server";
break;
default:
message = "Something went wrong";
break;
}
}
String message;
String _handleError(int statusCode, dynamic error) {
switch (statusCode) {
case 400:
return 'Bad request';
case 404:
return error["message"];
case 500:
return 'Internal server error';
default:
return 'Oops something went wrong';
}
}
#override
String toString() => message;
}
Please try passing the params as JSON encoded.
Response response = await dio.post(url, data: json.encode(params));
Hope this helps!
I had the same error, the BaseOptions was having different method name, other than POST... when i changed it back to POST it worked. Not sure if DIO package accepts using other than POST methods to call a Post method in API.
So I had this issue. So I found out that the headers you use in Postman should match the headers you are using in Dio. Like for example
headers: {
'Accept': "application/json",
'Authorization': 'Bearer $token',
},
and my Postman looks like this Postman
Apparently Dio behaves like postman when it comes to headers too so apparently if the headers from postman mis-match then it will throw an error.
Well in plain terms Dio would infer the content-type by itself just like postman would do.
Try to pass content type
final response = await Dio().post(Url,
options: Options(contentType: 'multipart/form-data'), data: formData);
This particular problem occurs when the response you expect (in JSON) doesn't match the response you are looking forward to receiving.
if this is your code,
Response response = await dio.post(url, data: params);
Check the Response model if it matches with the JSON it receives in the Postman response.
i had the same error the problem come from your server. your action to the server may be get datas [FromBody] use [FromForm] it will work. for me i resolved like that
eg public DataResponseModel UpdateFormalize([FromForm] FormalizeDto dto){
//somes code
}
While using http package in my flutter app, I encountered a slight issue. I am testing on localhost and when I post something in database using http.post, it doesn't return response for default time (i.e. 60s I think) when server is not running. And when I start the apache and mysql services within the timeout, it posts the data in the server . Is there any way to reduce the timeout of the http requests in dart http package? Or is there any alternative solution?
This is for http package
final response = await http.post(Url).timeout(Duration(seconds: 5));
And this is for Dio package (recommend to test this package)
BaseOptions options = new BaseOptions(
baseUrl: baseUrl,
connectTimeout: 10000, //10 seconds
receiveTimeout: 10000,
);
Dio dio = new Dio(options);
Response<dynamic> response = await dio.post(url, data: mapData);
You have two options availabe.
Reduce the timeout on the HttpClient
final client = new HttpClient();
client.connectionTimeout = const Duration(seconds: 10);
This will apply to all request made by the same client. If the request exceeds this timeout, a SocketException is thrown.
Set a per request timeout
You can set a timeout on any Future using the Future.timeout method.
try {
..
final request = await client.get(...);
final response = await request.close().timeout(const Duration(seconds: 10));
// more code
} on TimeoutException catch (e) {
// handle timeout
}
I'm trying to make a demo app with flutter and trying to fetch products from a demo magento site.
This is my code:
Future<List<Product>> fetchProducts() async {
final params = <String, String>{
'searchCriteria[filter_groups][0][filters][0][condition_type]': 'in',
'searchCriteria[filter_groups][0][filters][0][field]': 'type_id',
'searchCriteria[pageSize]': '20',
'searchCriteria[filter_groups][0][filters][0][value]': 'simple,configurable,bundle',
'searchCriteria[currentPage]': '1',
'searchCriteria[sortOrders][0][field]': 'created_at',
'searchCriteria[sortOrders][0][direction]': 'DESC'
};
var uri = Uri.parse('https://demo.com/rest/v1/default/products');
uri = uri.replace(queryParameters: params);
print(uri);
final response =
await http.get(uri, headers: {HttpHeaders.authorizationHeader: "Bearer qb7157owxy8a29ewgogroa6puwoafxxx"});
if (response.statusCode == 200) {
// If the call to the server was successful, parse the JSON.
final data = json.decode(response.body);
final products = data["items"] as List;
return products.map<Product>((json) => Product.fromJson(json)).toList();
} else {
// If that call was not successful, throw an error.
throw Exception('Failed to load post');
}
}
When I debugged, the response was 400 - Bad request. I guess that because the uri was encoded to include percentage characters as I printed as below:
So how can I disable encoding the uri?
Thank you, guys.
I believe you should replace:
var uri = Uri.parse('https://demo.com/rest/v1/default/products');
uri = uri.replace(queryParameters: params);
print(uri);
with:
var uri = Uri.https('demo.com', '/rest/v1/default/products', params);
more on this: Uri.https
more on: replace
example result:
regardless of this, if I try with your params, the library behaves normal and encodes the special characters. (see more here)
if we put the actual request in the browser to check the response:
https://demo.mage-mobile.com/rest/v1/default/products?searchCriteria[filter_groups][0][filters][0][condition_type]=in&searchCriteria[filter_groups][0][filters][0][field]=type_id&searchCriteria[pageSize]=20&searchCriteria[filter_groups][0][filters][0][value]=simple%2Cconfigurable%2Cbundle&searchCriteria[currentPage]=1&searchCriteria[sortOrders][0][field]=created_at&searchCriteria[sortOrders][0][direction]=DESC
we get the following response:
And this brings me to my initial suspicion: the API does not support this call.
Maybe you should also check this type of param from your code: 'searchCriteria[filter_groups][0][filters][0][condition_type]', it seems you are trying to acces some information from a collection but you actually writing a string...
try removing the quotes (' bla bla ') from these params id... also try to put the request direcly in the browser(or postman) to see it work.
About the encoding (changing [ to %5B) -- this is normal and it should happen.
I'm working on creating a Flutter application that works with LIFX. I'm trying to follow their instructions here, but I'm having issues adding a header to my HTTP GET request.
TestHttpGet() async {
var httpClient = new HttpClient();
var header = "Bearer $token"; //token hidden
var url = 'https://api.lifx.com/v1/lights/all/state';
String result;
try {
var request = await httpClient.getUrl(Uri.parse(url));
request.headers.set("Authorization", header);
var response = await request.close();
if (response.statusCode == HttpStatus.OK) {
var json = await response.transform(UTF8.decoder).join();
print(json);
var data = JSON.decode(json);
result = data['brightness'].toString();
} else {
result =
'Error getting response:\nHttp status ${response.statusCode}';
}
} catch (exception) {
result = 'Failed parsing response';
}
This returns with Error getting response: Http status 404. I've tried various ways of request.headers .set .add [HttpHeaders.Authorization] = "header" all return with a 404. Any advice would be appreciated.
You can pass a Map<String, String> to the http.get call as the headers parameter like this:
await httpClient.get(url, headers: {
'Authorization': 'Bearer $token',
});
In order to set headers you can't set the entire variable since it is set as final. What you need to do is set the value of the individual array items which are also known as the individual "headers" in this case.
For example :
http.Request request = http.Request('GET', uri);
request.headers['Authorization'] = 'Bearer $token';
I believe dart makes all the fields of a HttpHeader to lowercase.
https://github.com/flutter/flutter/issues/16665
The argument for that is because "Field names are case-insensitive". (otherwise it is not HTTP compliant)
https://www.rfc-editor.org/rfc/rfc2616#section-4.2
Let me know if you found a workaround for this.