Dart - print all response headers - dart

My Dart code send a form via post method to my GAE python server. I would like to see all headers return by the server in the response. but I can't perform that. Could you help?
void _httpRequest(url, datas){
HttpRequest request = new HttpRequest()
..open("POST", url, async: true)
..setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
..responseType = "";
// add an event handler that is called when the request finishes
request.onReadyStateChange.listen((_) {
if (request.status == 200) {
_onSuccess(request.responseText);
}else{
_handleTheError(request.responseText);
}
});
request.send(datas);
}
void _onSuccess(msg){
print("success : $msg");
}
void _handleTheError(msg){
print("error : $msg");
}

request.responseHeaders.forEach((k, v) {
print('Header: $k, value: $v');
});

Related

Dart server side: How to receive data from the Postman (form-data)?

I am using dart:io to create the server. I send the request from the Postman with form-data. I need to use form-data because my old API from another language uses it and the app uses it too.
At the moment. I am trying to get the data and files with this code:
Future main(List<String> arguments) async {
HttpServer server = await HttpServer.bind('localhost', 8085);
server.listen((HttpRequest request) async {
String jsonString = await request.cast<List<int>>().transform(utf8.decoder).join();
print("jsonString:\n$jsonString");
await request.response.close();
});
}
When I send the data and a file from the Postman with this below.
I will get the error below.
Unhandled exception:
FormatException: Unexpected extension byte (at offset 435)
If I don't send the file as image 1, I got this.
jsonString:
----------------------------166099235909119466948633
Content-Disposition: form-data; name="key 1"
Content-Type: application/json
value 1
----------------------------166099235909119466948633
Content-Disposition: form-data; name="key 2"
value 2
----------------------------166099235909119466948633--
I can't convert the above results to variables.
I don't know how to do that. Has anyone an example for doing this or suggest any package to me? This is my first time creating a dart server.
I follow this.
You can get the data and files from the request by using shelf_multipart (Other packages may be used in conjunction with this one and find more methods on GitHub).
If you want to see results quickly that it can be done. Follow this below.
I am using 3 packages including the shelf, shelf_router, and shelf_multipart packages.
You need to add these packages to your pubspec.yaml.
(You can copy and paste these into your pubspec.yaml.)
dependencies:
shelf: ^1.4.0
shelf_router: ^1.1.3
shelf_multipart: ^1.0.0
Then copy my code and past it to your main.dart:
import 'dart:convert';
import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart' as shelf_io;
import 'package:shelf_router/shelf_router.dart';
import 'package:shelf_multipart/form_data.dart';
import 'package:shelf_multipart/multipart.dart';
Future main(List<String> arguments) async {
final service = Service();
final server = await shelf_io.serve(service.handler, 'localhost', 8085);
print('Server running on localhost:${server.port}');
}
class Service {
Handler get handler {
final router = Router();
router.post("/example", (Request request) async {
if (request.isMultipart && request.isMultipartForm) {
Map<String, dynamic>? data = await RequestConverter.formData(request);
return data != null
? Response.ok("form-data: true, receive-data: true, data: $data")
: Response.ok("form-data: true, receive-data: false");
}
return Response.ok("form-data: false");
});
router.all('/<ignored|.*>', (Request request) {
return Response.notFound('Page not found');
});
return router;
}
}
class RequestConverter {
static Future<Map<String, dynamic>?> formData(Request request) async {
try {
Map<String, dynamic> data = {};
Map<String, dynamic> files = {};
final List<FormData> formDataList = await request.multipartFormData.toList();
for (FormData formData in formDataList) {
if (formData.filename == null) {
String dataString = await formData.part.readString();
data[formData.name] = Json.tryDecode(dataString) ?? dataString; //Postman doesn't send data as json
} else if (formData.filename is String) {
files[formData.name] = await formData.part.readBytes();
}
}
return {"data": data, "files": files};
} catch (e) {
return null;
}
}
}
class Json {
static String? tryEncode(data) {
try {
return jsonEncode(data);
} catch (e) {
return null;
}
}
static dynamic tryDecode(data) {
try {
return jsonDecode(data);
} catch (e) {
return null;
}
}
}
After this, you can start your server in your terminal. For me I am using:
dart run .\bin\main.dart
Finally, open the Postman and paste http://localhost:8085/example to the URL field, select the POST method, and form-data. You can add the data into the KEY and VALUE fields. Then press send.
This is my example in the Postman:
This solution work with http.MultipartRequest() from the Flutter app.

Network Error React Native on IOS Production

I am facing an issue with a react native app in production. Some request fails and other go through. The issue happens to a lot of users and it's random. Only happens to our ios app and not our android app. The device has internet because we have #react-native-community/netinfo logging every time the network changes and in almost all the cases is not logging any change (there are some times that the user losses internet in which case it's fine the network error).
We use sentry to log app errors. In the image below you can see the device makes a post request to our API and very quickly it goes to response interceptor error.
In the tags image you can see that the problem only occurs on release 5.3.3 but I don't know what is causing this from this release. I have not changed anything from axios request.
Since I don't have a reputation of 10 I cannot post images but here are the links.
Network Issue Report: https://i.postimg.cc/PJWjvCvt/Screen-Shot-2022-06-16-at-11-25-06-AM.png
Image of sentry tags: https://i.postimg.cc/Y0NSBr7s/Screen-Shot-2022-06-16-at-11-43-37-AM.png
This is our axios interceptor:
const axiosInstance = axios.create({
baseURL: ENV.API_URL,
headers: {
Accept: "application/json",
"Content-Type": "application/json"
}
});
axiosInstance.interceptors.request.use(async function (config) {
config.headers['device-app-version'] = DeviceInfo.getVersion();
try {
const token = await AsyncStorage.getItem('token');
if (token) {
config.headers['authorization'] = "JWT " + token;
}
} catch (error) {
console.log("ERROR GET ASYNCSTORAGE DATA FAILED ON TOKEN", error);
}
const httpMetric = firebase.perf().newHttpMetric(config.url, config.method.toUpperCase());
config.metadata = { httpMetric };
await httpMetric.start();
return config;
}, function (error) {
console.log("Request interceptor error");
console.log(error);
return Promise.reject(error);
});
axiosInstance.interceptors.response.use(async function (response) {
const { httpMetric } = response.config.metadata;
if (response.status != 200) {
Sentry.withScope(function(scope) {
scope.setTag('API', response.config.url);
scope.setExtra('API', response.config.url);
scope.setFingerprint(['API', response.config.url]);
Sentry.captureException(response);
});
}
httpMetric.setHttpResponseCode(response.status);
httpMetric.setResponseContentType(response.headers['content-type']);
await httpMetric.stop();
return response;
}, async function (error) {
const { httpMetric } = error.config.metadata;
console.log("Response interceptor error");
console.log(error);
console.log("error.response");
console.log(error.response);
const scope = new Sentry.Scope();
if (error.response) {
// Request made and server responded
console.log(error.response.data);
console.log(error.response.headers);
console.log("Status:", error.response.status);
if (error.response.status == 403) {
return Promise.reject(error);
}
scope.setTag('API', error.response.config.url);
scope.setExtra('API', error.response.config.url);
scope.setFingerprint(['API', error.response.config.url]);
Sentry.captureException(error.response, scope);
} else if (error.request) {
// The request was made but no response was received
console.log(error.request);
Sentry.captureException(error.request, scope);
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error', error.message);
Sentry.captureException(error.message, scope);
}
httpMetric.setHttpResponseCode(error.response.status);
httpMetric.setResponseContentType(error.response.headers['content-type']);
await httpMetric.stop();
if (!error.response) {
error.response = {
data: [],
status: 401,
message: 'Error ocurred making request. Try again'
}
}
return Promise.reject(error);
},
);
Package.json (affected packages)
"axios": "^0.26.1",
"react": "17.0.2",
"react-native": "0.66.1",

How can I prevent Dio from throwing an error after successfully retrying?

I'm using Dio to do requests to a REST-api. When the authorization token expires, I refresh the token and resend the request. The code to do that looks like this:
onError: (DioError error, ErrorInterceptorHandler handler) async {
logger.d(errorLogString(error));
if (error.response?.statusCode == 401 && error.requestOptions.path != 'login' && _retries-- > 0) {
await authService.refreshToken();
error.response = await dio.request(
error.requestOptions.path,
data: error.requestOptions.data,
queryParameters: error.requestOptions.queryParameters,
options: Options(
method: error.requestOptions.method,
headers: error.requestOptions.headers,
),
);
}
return handler.next(error);
},
This works okay, but Dio still throws an error even if the new request is successful, which means that I have to catch and check the status code for each request. For example like this:
try {
final response = await dio.post(
'someUrl',
);
return Object.fromJson(response.data);
} catch (error) {
if(error is DioError && (error.response?.statusCode ?? 300) < 300){
return Object.fromJson(error.response!.data);
}
throw parseError(error);
}
Is there any way that I can prevent Dio from trowing an error at all when the request is successfull, or do I have to catch the error each time like I do above. In that case, is there a way to simplify the process of catching the error and returning the successful response?
I know this is an old question but in case anyone else is looking for the answer to this like I was today, you can use handler.resolve(response)
Using the above example:
onError: (DioError error, ErrorInterceptorHandler handler) async {
logger.d(errorLogString(error));
if (error.response?.statusCode == 401 && error.requestOptions.path != 'login' && _retries-- > 0) {
await authService.refreshToken();
var response = await dio.request(
error.requestOptions.path,
data: error.requestOptions.data,
queryParameters: error.requestOptions.queryParameters,
options: Options(
method: error.requestOptions.method,
headers: error.requestOptions.headers,
),
);
return handler.resolve(response);
}
return handler.next(error);
},

HTTP Post passing 2 parameters and content type key flutter

I am struggling with making a http post call returning JSON in flutter. I keep getting a 500 error and I dont know what the issue is. I need to pass a username and password in the header and I think the issue is how im doing it. Here is the code.
Future<User> LoginUser(String username, String password ) async {
final response =
await http.post('http://xx.xxx.xxx.xxx/api/Login',
headers: {"Content-Type": "application/json", 'email' : username , 'password' : password });
if (response.statusCode == 200) {
// If the call to the server was successful, parse the JSON
return User.fromJson(json.decode(response.body));
} else {
// If that call was not successful, throw an error.
throw Exception('Failed to load user');
}
}
It wont get past the 200 check because it is getting a 500. I cant find any examples with passing 2 parameters in the header and the content type so im not sure im doing that correctly.
If we have to pass 2 arguments like key and any other data, Then follow the code(Only for Post Request)
Future<ClassType> callApi()async{
const String url="your/request/to/post/link/url";
const Uri=Uri.parse(url);
Map passValues={'token':'yOuRtOkEnkEy','user_id':'123456789'};
var body = json.encode(token);
var response;
try {
response = **await** http.post(
uri,
headers: {'Content-Type': 'application/json'},
body: body,
);
} catch (e) {
print(e);
}
if (response.statusCode == 200) {
var jsonString = response.body;
var jsonMap = json.decode(jsonString);
print(jsonMap);
} else {
print('API FAILED');
}
return response;
}

Backbone.js: POST request with empty value

I am trying to make a POST request.
Here my code:
var myModel = new MydModel({
content: "ciao"
});
console.log(myModel.get("content")); // "ciao"
myModel.save();
If I look to the network activity it looks like this:
The response part {id:0, content:"", ……}
In the header part: Request Payload {"content":"ciao"}
Here my model:
define([], function () {
var MyModel = Backbone.Model.extend({
url: function url ()
{
return "http://localhost/users";
}
});
return MyModel;
});
Is it my problem or is it in the server part?
send/receive vs request/response
a server receives requests and sends responses
a client sends requests and receives responses
in short
if {id:0, content:"", ……} (the response) is wrong, it's your server
if {"content":"asdasdsa"} (the request) is wrong, it's your client
There is little problem with receiving JSON-payload that "Backbone-client" sends to your Apache-server.
All you need to do is to manually parse JSON-payload from input on the server side ("php://input", for PHP), like this:
if($_SERVER['REQUEST_METHOD'] == 'PUT' || $_SERVER['REQUEST_METHOD'] == 'POST') {
$postStr = file_get_contents("php://input");
//json_decode throws error or returns null if input is invalid json
try {
$json = json_decode($postStr, true);
if(empty($json)) {
throw new Exception("Not valid json");
}
//must not be json, try query str instead
} catch(Errfor $e) {
$postVars = parse_str($postStr);
foreach($postVars as $key=>$data) {
$_POST[$key] = $data;
}
}
}
Full explanation you can find here:
http://colinbookman.com/2014/04/08/php-puts-posts-and-backbone-js/

Resources